Install
$ agentstack add skill-scholarly360-owasp-top10-web-skills-software-data-integrity-failures Open-source listing — not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Dangerous shell/eval execution.
What it can access
- ● Network access Used
- ● Filesystem access Used
- ● Shell / process execution Used
- ● Environment & secrets Used
- ● Dynamic code execution Used
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
A08:2025 — Software or Data Integrity Failures
Overview
OWASP rank: #8 (2025) | CWEs covered: 14 | Avg incidence: 2.75%
This category focuses on failure to verify integrity of software, code, and data artifacts within your own environment — distinct from A03's upstream supply chain focus. The core concern is: can you trust what you're loading, deserializing, or executing?
Key distinction from A03 (Supply Chain):
- A03 = upstream integrity (your dependencies, CI/CD pipelines)
- A08 = runtime integrity (what you actually deserialize, include, or auto-update at runtime)
Critical Risk Areas for Python
1. Insecure Deserialization — The #1 Python-Specific Risk
pickle.loads() on untrusted input equals arbitrary code execution via __reduce__. This is the single most dangerous A08 vector in Python.
Dangerous functions/modules to flag:
| Module / Function | Risk | Safe Alternative | |---|---|---| | pickle.loads() / pickle.load() | RCE via __reduce__ | JSON + Pydantic | | cPickle.loads() | Same as pickle | JSON + Pydantic | | dill.loads() | Superset of pickle, same RCE risk | JSON + Pydantic | | jsonpickle.decode() | Deserializes Python objects | json.loads() only | | shelve.open() | Backed by pickle | Redis/SQL store | | yaml.load(data, Loader=None) | Code execution via !!python/object | yaml.safe_load() | | numpy.load(f, allow_pickle=True) | RCE via pickled arrays | allow_pickle=False | | torch.load(f) | Pickle-backed by default | weights_only=True |
Detection pattern (static analysis):
# Flag any of these patterns in source code
DANGEROUS_PATTERNS = [
r'pickle\.loads?\(',
r'cPickle\.loads?\(',
r'dill\.loads?\(',
r'jsonpickle\.decode\(',
r'shelve\.open\(',
r'yaml\.load\([^)]*(?!safe_load)',
r'numpy\.load\([^)]*allow_pickle\s*=\s*True',
r'torch\.load\([^)]*(?!weights_only\s*=\s*True)',
]
If pickle is unavoidable — HMAC integrity check:
import hmac, hashlib, pickle, os
SECRET = os.environ["PICKLE_HMAC_SECRET"].encode()
def safe_serialize(obj) -> bytes:
data = pickle.dumps(obj)
mac = hmac.new(SECRET, data, hashlib.sha256).digest()
return mac + data # prepend 32-byte MAC
def safe_deserialize(payload: bytes):
mac, data = payload[:32], payload[32:]
expected = hmac.new(SECRET, data, hashlib.sha256).digest()
if not hmac.compare_digest(mac, expected):
raise ValueError("Integrity check failed — data tampered")
return pickle.loads(data)
2. Mass Assignment (CWE-915)
Occurs when request.json or form data is passed directly into ORM .update() without field filtering — allowing attackers to set fields like is_admin=True or role="superuser".
Flask — Vulnerable pattern:
# ❌ DANGEROUS — attacker can inject any field
user = User.query.get(user_id)
user.__dict__.update(request.json)
db.session.commit()
# Also dangerous:
User.query.filter_by(id=user_id).update(request.json)
Flask — Safe pattern:
# ✅ SAFE — explicit allowlist
ALLOWED_FIELDS = {"name", "email", "bio"}
data = {k: v for k, v in request.json.items() if k in ALLOWED_FIELDS}
User.query.filter_by(id=user_id).update(data)
FastAPI — Pydantic prevents mass assignment by default:
# ✅ FastAPI with Pydantic — only declared fields accepted
class UserUpdate(BaseModel):
name: str | None = None
email: str | None = None
bio: str | None = None
# is_admin, role etc. cannot be set — they're not in the schema
@router.patch("/users/{user_id}")
async def update_user(user_id: int, body: UserUpdate, db: Session = Depends(get_db)):
db.query(User).filter(User.id == user_id).update(body.model_dump(exclude_unset=True))
Detection pattern: In Flask, scan for request.json or request.form flowing into .update(), __dict__.update(), or ORM bulk-update calls without an intermediate allowlist filter.
3. Subresource Integrity (SRI) for External Scripts/Styles
If your Flask/FastAPI app renders HTML templates that load scripts or stylesheets from external CDNs, those resources must include SRI hashes to prevent CDN compromise from injecting malicious code.
Vulnerable Jinja2 template:
Secure Jinja2 template:
How to generate SRI hashes:
# Using openssl
curl -sL https://cdn.example.com/lib.js | openssl dgst -sha384 -binary | openssl base64 -A
# Or use srihash.org / unpkg.com automatically provides them
Detection: Scan Jinja2/HTML templates for ` and tags missing integrity=` attributes.
4. Auto-Update Without Verification (CWE-494)
Applications that download and execute code/config updates without verifying a cryptographic signature are vulnerable to man-in-the-middle attacks.
Pattern to flag:
# ❌ Downloads and executes without verification
import urllib.request, subprocess
urllib.request.urlretrieve("https://example.com/update.sh", "/tmp/update.sh")
subprocess.run(["bash", "/tmp/update.sh"])
# ❌ Loads remote config without integrity check
import json, urllib.request
config = json.loads(urllib.request.urlopen("https://config.example.com/settings.json").read())
Safe pattern — signature verification:
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
import urllib.request
def download_and_verify(url: str, sig_url: str, public_key_path: str) -> bytes:
data = urllib.request.urlopen(url).read()
sig = urllib.request.urlopen(sig_url).read()
with open(public_key_path, "rb") as f:
pubkey = serialization.load_pem_public_key(f.read())
pubkey.verify(sig, data, padding.PKCS1v15(), hashes.SHA256()) # raises on failure
return data
Testing Checklist
Use this checklist when auditing a FastAPI or Flask application for A08 compliance:
Deserialization
- [ ] No
pickle.loads()/pickle.load()on untrusted input - [ ] No
cPickle,dill,jsonpickle.decode()on untrusted input - [ ]
yaml.safe_load()used instead ofyaml.load() - [ ]
numpy.load()called withallow_pickle=False - [ ]
torch.load()called withweights_only=True - [ ]
shelvenot used with untrusted keys/data - [ ] If pickle unavoidable: HMAC pre-verification implemented
Mass Assignment
- [ ] Flask: no
request.jsonpassed directly into ORM.update()without allowlist - [ ] Flask: no
model.__dict__.update(untrusted_data)patterns - [ ] FastAPI: Pydantic models used for all request bodies (prevents by default)
- [ ] Privileged fields (
is_admin,role,balance) not in public update schemas
External Integrity
- [ ] All external `
tags haveintegrity=` SRI attributes - [ ] All external `
tags haveintegrity=` SRI attributes - [ ] Remote downloads verified with cryptographic signature or hash before execution
- [ ] No dynamic
eval()orexec()on remotely fetched content
CI/CD Integrity (boundary with A03)
- [ ] Code review required for all changes to deployment config/scripts
- [ ] Build artifacts signed and signature verified before deployment
- [ ] CI/CD secrets not accessible to pull request pipelines from forks
Automated Scanning Tools
| Tool | What it catches | How to run | |---|---|---| | Bandit | pickle, yaml.load, subprocess, eval | bandit -r . -t B301,B302,B506 | | Semgrep | Deserialization, mass assignment patterns | semgrep --config=p/python | | pip-audit | Known-vulnerable deserialization libs | pip-audit | | Manual grep | Quick sweep for dangerous functions | See patterns in section 1 |
Bandit rule IDs for A08:
B301—pickleusageB302—marshalusage (similar risk)B506—yaml.loadwithout safe loaderB403—pickleimport (informational)
Key CWEs
| CWE | Description | Primary Vector | |---|---|---| | CWE-502 | Deserialization of Untrusted Data | pickle, yaml, jsonpickle | | CWE-915 | Improperly Controlled Modification of Dynamically-Determined Object Attributes | Mass assignment | | CWE-829 | Inclusion of Functionality from Untrusted Control Sphere | CDN scripts without SRI | | CWE-345 | Insufficient Verification of Data Authenticity | Missing HMAC/signature checks | | CWE-494 | Download of Code Without Integrity Check | Auto-update without verification |
References
- OWASP A08:2025 — Software and Data Integrity Failures
- Python Pickle Security
- SRI Hash Generator
- Bandit SAST for Python
- See
references/deserialization-exploits.mdfor exploit PoCs and deeper analysis
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: scholarly360
- Source: scholarly360/owasp-top10-web-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.