software-data-integrity-failures
Skill23 starsChanged 7 months agoMITView on GitHub
Security testing skill for OWASP A08:2025 — Software or Data Integrity Failures in Python web applications (FastAPI and Flask). Use this skill whenever the user wants to audit, detect, test, or fix integrity vulnerabilities including: insecure deserialization (pickle, yaml, jsonpickle, dill), mass assignment flaws, untrusted CDN/module inclusion, unsigned updates, CI/CD pipeline integrity, or Subresource Integrity (SRI) checks. Trigger this skill for ANY task involving pickle/deserialization security, CWE-502, CWE-915, CWE-829, CWE-345, or CWE-494, even if the user doesn't explicitly mention OWASP A08.
In this repository9 other files it gives its agents.
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 2 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 125
If your Flask/FastAPI app renders HTML templates that load scripts or stylesheets from external CDNs, those resources must include SRI …
- Distinctive: line 190
Use this checklist when auditing a FastAPI or Flask application for A08 compliance:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
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:
<!-- ❌ No integrity check — CDN compromise = XSS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>Secure Jinja2 template:
<!-- ✅ SRI hash prevents tampered CDN delivery -->
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
crossorigin="anonymous">
</script>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 themDetection: Scan Jinja2/HTML templates for <script src="https://..."> and <link href="https://..."> 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 dataTesting 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=Falsetorch.load()called withweights_only=Trueshelvenot 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
<script>tags haveintegrity=SRI attributes - All external
<link rel="stylesheet">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
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

