A08 Software or Data Integrity Failures
If the program accepts updates, plugins, serialized objects or pipeline output without proving where they came from, whoever can alter them can run code as you.
What it is
Integrity failures happen when code or data is trusted without verification: auto-updates that are not signed, scripts loaded from a CDN with no integrity check, deserialization of untrusted bytes, and CI/CD pipelines where one compromised step can alter what ships.
:2025 keeps this category as A08. It is close to A03 (supply chain) but focuses on the verification step: can you prove that what you run is what was meant to run?
How the attack works
- : the application rebuilds objects from attacker-supplied bytes (Java serialization, Python pickle, unsafe YAML), and the stream triggers code execution.
- Tampered update or plugin: a download over an unsigned channel is replaced in transit or on the mirror.
- Unchecked third-party script: a compromised CDN serves modified JavaScript to every visitor.
- Client-controlled state: a cookie or hidden field that carries a role, price or object is edited and accepted.
Vulnerable code
Deserializing untrusted bytes with pickle, trusting a user-editable cookie, and loading a script with no integrity attribute.
import pickle, base64
def load_prefs(cookie):
return pickle.loads(base64.b64decode(cookie)) # attacker-controlled bytes run codeconst cart = JSON.parse(Buffer.from(req.cookies.cart, "base64").toString());
total = cart.total; // the client wrote this number<script src="https://cdn.example.com/lib/chart.min.js"></script>The fix
Use data-only formats (JSON) with schema validation, never native object serialization for untrusted input. If state must round-trip through the client, sign it (HMAC or a signed token) and verify before use, or better, keep it on the server. Pin third-party scripts with , and verify signatures on anything you install or update.
import hmac, hashlib, json, base64
SECRET = load_secret("PREFS_HMAC_KEY")
def dump_prefs(prefs: dict) -> str:
body = base64.urlsafe_b64encode(json.dumps(prefs).encode())
mac = hmac.new(SECRET, body, hashlib.sha256).hexdigest().encode()
return (body + b"." + mac).decode()
def load_prefs(cookie: str) -> dict:
body, _, mac = cookie.encode().partition(b".")
expected = hmac.new(SECRET, body, hashlib.sha256).hexdigest().encode()
if not hmac.compare_digest(mac, expected):
raise ValueError("tampered")
return json.loads(base64.urlsafe_b64decode(body)) # data only, validated after// state lives on the server; the cookie only carries an opaque id
const cart = await carts.get(req.session.cartId);
const total = cart.items.reduce((s, i) => s + catalog.price(i.sku) * i.qty, 0);<script src="https://cdn.example.com/lib/chart-4.4.1.min.js"
integrity="sha384-<hash of the exact file>"
crossorigin="anonymous"></script># the artifact must be signed by the expected pipeline identity
cosign verify-blob --certificate-identity 'https://github.com/example/app/.github/workflows/release.yml@refs/heads/main' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--signature app.tgz.sig --certificate app.tgz.pem app.tgzProve the fix
Feed the code exactly what an attacker would: a modified cookie, a payload from a deserialization gadget, and a changed script file. The correct outcome is rejection, with no code executed.
def test_tampered_cookie_is_rejected():
cookie = dump_prefs({"theme": "dark"})
body, mac = cookie.split(".")
forged = base64.urlsafe_b64encode(b'{"theme":"dark","role":"admin"}').decode() + "." + mac
with pytest.raises(ValueError):
load_prefs(forged)
def test_pickle_payload_is_not_executed(tmp_path):
marker = tmp_path / "pwned"
class Evil:
def __reduce__(self):
return (open, (str(marker), "w"))
payload = base64.b64encode(pickle.dumps(Evil())).decode()
with pytest.raises(Exception):
load_prefs(payload)
assert not marker.exists()# every external <script> and <link rel=stylesheet> must carry an integrity attribute
! grep -RInE '<script[^>]+src="https?://' dist/ | grep -v 'integrity='Checklist
- Never deserialize untrusted data with a format that can instantiate objects; prefer JSON plus schema validation.
- Sign anything that must cross a (cookies, update files, messages) and verify before use.
- Use Subresource Integrity for third-party scripts and styles, or self-host them.
- Sign build artifacts and container images; verify the signature at deploy time.
- Protect the pipeline: reviewed changes, separate build and deploy permissions, no unreviewed code in release steps.
- Prefer server-side state for prices, roles and permissions.
connections on the map
- A03 Software Supply Chain Failuresis stopped by verifyingA08 Software or Data Integrity Failures
updated on 14/10/2026 · sources to go deeper · report an error
in other domains
- CI/CD hardeningsecengthe pipeline is part of what must be kept intact
Study before
test what you learned
Loading questions…