A map of which functions call which other functions in an application and its dependencies. Security tools use it to trace whether a vulnerable function sits on a live execution path or remains unreachable in practice.
What a call graph shows
A call graph is a structural map of function-to-function invocation inside an application and, often, its dependencies. It shows the potential execution routes through code, which makes it useful for understanding where behaviour can actually flow rather than where code merely exists.
For security analysis, that distinction matters because a vulnerable function only becomes exploitable if an execution path can reach it under real conditions. A call graph helps separate reachable attack surface from dead code, test-only paths, and dependency functions that are present but not practically invoked.
Why call graphs matter for vulnerability reachability
Security teams use call graphs to answer a simple but important question: is a risky function on a live path from an entry point, or is it isolated? That makes the call graph a practical input to reachability analysis, software composition analysis, and exploitability triage.
In dependency-heavy applications, the same package can contain many functions, but only a small subset may ever be called by the running service. A call graph reduces noise by showing how one function can lead to another through direct calls, helper methods, wrappers, callbacks, and transitive library use.
That is also why call graph analysis is often paired with evidence about runtime behaviour. Static graphs are valuable, but they can overstate reachability when configuration, feature flags, input conditions, or deployment topology make a path unreachable in practice.
How call graphs are built and interpreted
Call graphs may be generated statically from source or bytecode, dynamically from observed execution, or by combining both approaches. Static graphs usually have broader coverage, while dynamic graphs can confirm what actually ran in a given workload. In mature analysis, teams compare both views to understand coverage gaps and execution reality.
Interpretation depends on the quality of the program model. Indirect calls, reflection, dynamic dispatch, callbacks, and generated code can all make a graph incomplete or overly conservative. A useful call graph is therefore not just a diagram, but a reasoned estimate of possible execution based on the language runtime, build artefacts, and analysis method.
Because of that, call graphs are most valuable when treated as decision support rather than as absolute proof. They help analysts prioritise what deserves deeper inspection, especially when a finding appears in a dependency but may never be invoked in the application's actual call chain.
Call graphs in secure development and dependency analysis
Call graphs support secure development by showing where sensitive logic sits in relation to entry points, privilege boundaries, and external inputs. They are especially useful when reviewing third-party libraries, shared utility modules, and framework code that may carry vulnerabilities but is only dangerous if the application actually invokes the affected function.
They also help teams explain why two scans can produce very different risk pictures. One scan may list a vulnerable package as present, while call graph analysis shows that the vulnerable function is unreachable in the deployed service. Conversely, a shallow scan may miss a path that a deeper graph reveals, especially where wrapper functions or nested dependencies hide the true execution chain.
Used well, a call graph turns vulnerability management from simple package counting into execution-path reasoning. That improves prioritisation, reduces unnecessary remediation work, and gives teams a stronger basis for documenting why a reported issue is or is not exploitable.
Risk and Threat Considerations
Call graphs reduce uncertainty, but they can also create false confidence if the analysis is incomplete or stale. A missing edge, dynamic dispatch, or configuration-dependent path can hide a real execution route, while a conservative graph can make unreachable code look exposed.
Failure mechanism: Attackers benefit when defenders assume a function is unreachable without validating the analysis method, runtime conditions, and deployment context. If the graph misses an invocation path, a vulnerable routine may remain in production longer than expected and still be reachable through an overlooked code path.
Impact: Incorrect reachability conclusions can distort patch priority, delay remediation, and leave exploitable logic in place even after teams believe they have triaged it. In practice, the risk is not the diagram itself, but the operational decision made from an incomplete one.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
CIS Controls v8, NIST SP 800-53 Rev 5 and OWASP ASVS set the technical controls, while ISO/IEC 27001:2022 defines the regulatory obligations.
| Framework | Control / Reference | Relevance |
|---|---|---|
| CIS Controls v8 | CIS-16 — Application Software Security | Call graph analysis supports secure code review and exploitability prioritisation. |
| Recommendation — Use application security testing and code review to validate which vulnerable functions are reachable. | ||
| NIST SP 800-53 Rev 5 | SA-11 — Developer Testing and Evaluation | Reachability analysis is part of evaluating whether code flaws are practically exposed. |
| Recommendation — Use SA-11 to test whether findings are reachable in the deployed execution path. | ||
| OWASP ASVS | V15 — Secure Coding and Architecture | Call graphs help assess architectural execution paths and hidden code exposure. |
| Recommendation — Review execution paths to ensure vulnerable code is not exposed through reachable architecture. | ||
| ISO/IEC 27001:2022 | A.8.29 — Security testing in development and acceptance | Call graph-driven reachability analysis supports security testing before release. |
| Recommendation — Include execution-path analysis in pre-release security testing to validate exploitability. | ||
Practitioner Guidance
Why practitioners should care: Treat call graphs as a reachability control, not just a visualisation. The most useful question is whether the graph supports a defensible decision about exploitability, not whether it simply lists function relationships.
What to watch for: Pay special attention to indirect calls, runtime-generated paths, and dependency code that is present but not obviously invoked. Those are the places where static analysis most often needs corroboration from build context or runtime evidence.
Practitioner takeaway: A good call graph should improve prioritisation, not merely increase confidence in a scan result. If it cannot support that decision, it is incomplete for security use.
Related resources from NHI Mgmt Group
- Guide: Reachability Analysis Guide
- Why do traditional source-sink and call-graph approaches miss so many application security issues in modern codebases?
- What is the difference between tool call policy and access graph enforcement in agent authorization?
- Why does call graph analysis matter when assessing library risk in Java applications?
- Reverse Call Graph
Deepen Your Knowledge
Free weekly newsletter
Subscribe to the NHI & AI Identity Journal
The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.
Bonus 33% off our NHI Course when you subscribe.
Reviewed and updated by the NHIMG editorial team on October 31, 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org