Prioritizing Risk: Why Only 36 of 39 CVEs in WebGoat Were Actually Reachable
These articles are AI-generated summaries. Please check the original sources for full details.
39 CVEs in WebGoat. Only 36 Were Reachable.
Engineer Ekene Ejike developed a reachability engine to address CI/CD pipeline blocks caused by excessive security alerts in a Spring Boot application. By running the engine against OWASP WebGoat, the analysis mapped 158,000 methods to identify which vulnerabilities could actually be executed. The result was a high-fidelity risk assessment that reduced manual triage from 39 potential issues to just one unknown case.
Why This Matters
Software Composition Analysis (SCA) tools typically flag any vulnerable version found in a dependency tree, regardless of whether the application ever invokes the affected code. This creates a massive gap between perceived risk and actual risk, leading to ‘alert fatigue’ and unnecessary deployment delays. Reachability analysis bridges this gap by using static call graphs to determine if a path exists from application entry points to the vulnerable method. While a reachable CVE does not guarantee exploitability, an unreachable one guarantees the code cannot execute, allowing engineering teams to focus limited resources on high-risk paths.
Key Insights
- NetShield Analyzer identified 36 reachable, 2 unreachable, and 1 unknown CVE in OWASP WebGoat (2026).
- Adjacency list implementation reduced call graph traversal complexity from O(V*E) to O(V+E), cutting analysis time from 33 minutes to 29 seconds.
- Framework-aware analysis is required to detect hidden entry points like Spring @Controller methods and Jakarta Servlet doGet/doPost calls.
- Static analysis of Java applications must perform class hierarchy traversal to resolve virtual dispatch and interface implementations.
- The engine uses OSV.dev (open) which flagged 39 CVEs, while Snyk (proprietary) identified 48, highlighting a database coverage gap rather than a reachability failure.
Working Examples
Direct call to a vulnerable deserialization entry point in WebGoat’s lesson code.
XStream xstream = new XStream();
Object obj = xstream.fromXML(payload);
Adjacency list optimization used to improve DFS performance by orders of magnitude.
func (cg *CallGraph) AddEdge(from, to string, callType CallType) {
cg.Edges = append(cg.Edges, &CallEdge{From: from, To: to, Type: callType})
cg.AdjList[from] = append(cg.AdjList[from], to)
}
Practical Applications
- Use Case: CI/CD integration where NetShield fails builds only for REACHABLE vulnerabilities, preventing unnecessary release blocks.
- Pitfall: Treating UNKNOWN results as safe; manual review is critical when reflection (Class.forName) or dynamic loading is involved.
- Use Case: Automating entry point discovery for REST APIs (JAX-RS @Path) and event-driven consumers (Kafka onMessage) to ensure call graph coverage.
References:
Continue reading
Next article
Andrew Ng's Team Launches Context Hub to Solve Coding Agent API Drift
Related Content
Automating Linux Vulnerability Scanning with Python and dpkg
Filter 41,000+ CVEs to identify actionable vulnerabilities on Linux servers using an 800-line Python matcher and dpkg version comparison.
Critical Security Alert: Node.js 18 and PHP 7.4 Reach End-of-Life
Millions of production apps are running on Node.js 18 and PHP 7.4, which reached end-of-life in 2025 and 2022 respectively, leaving them without security patches.
2026 EOL Roadmap: Managing Security Risks for 50 Critical Products
2026 marks a massive EOL cycle for 50 major products including Node.js 20, Java 17, and MySQL 8.0, creating critical unpatched CVE risks for legacy enterprise stacks.