Taint analysis follows untrusted data through a program and flags any
path on which it reaches a dangerous operation unsanitized. The
sources are where it enters: an HTTP parameter, a request body, a
file. The sinks are where it would do damage: a SQL query, a shell
command, eval, a file path, an outbound URL. A sanitizer on the
path between them clears the taint: escaping, a parameterized query,
allow-list validation. It is the core technique behind
injection-vulnerability detection. The model underneath is
information-flow security in its integrity form, the dual of
confidentiality: information must be prevented from flowing from
inappropriate sources (Sabelfeld and Myers 2003)1.
Static and dynamic¶
Two forms answer the same source→sink question. Static (SAST) traces taint through the code without running it — a specialization of static analysis built on interprocedural dataflow rather than a linter's one-file-at-a-time pattern matching. It finds paths the tests never exercised, at the cost of false positives on infeasible paths and unmodeled sanitizers. Meta runs its in-house engine Zoncolan on Hack and Pysa on Python as a diff-time security gate across its codebases.
Dynamic taint tracking instruments the running program instead, so it sees real execution and reports far fewer false positives, but only along the paths the traffic actually drives. This is the engine under IAST (interactive application security testing); RASP is the production-time counterpart, blocking a tainted flow instead of reporting it.
Sources, sinks, and sanitizers¶
The analysis is only as good as its model of sources, sinks, and sanitizers. A missing source or sink is a silent blind spot; a sanitizer the tool doesn't recognize is a false positive. Tuning them for a codebase and its frameworks is the work of applying the method.
What it catches¶
- Injection flaws. SQLi, command injection, XSS, path traversal, SSRF, unsafe deserialization — anywhere external input reaches a dangerous operation along an unsanitized path.
- Cross-procedure flows. Taint that passes through several functions, a field, or a collection between source and sink — which a local pattern rule cannot see.
Taint analysis does not reliably catch implicit (control-flow) flows, where a value leaks through which branch ran rather than through an assignment. Implicit flows are a covert channel, the kind of channel that poses the greatest challenge in preventing information leaks (Sabelfeld and Myers 2003)1. Most production tools ignore them.
Tools¶
Static (SAST):
- Multi-language: CodeQL runs interprocedural source→sink queries across many languages.
- Multi-language: Semgrep tracks taint within one function in its free Community Edition; tracking it across functions and files needs the commercial Semgrep Pro.
- Python: Pysa (Meta).
- Node.js: the research tool ODGen (Li et al. 2022)2 builds an object dependence graph by abstract interpretation and queries it both for source-to-sink flows and for object lookups along the prototype chain, which reaches prototype pollution, a vulnerability class unique to JavaScript.
Dynamic:
- Binary: Triton does dynamic taint for analysis and reverse engineering.
- Node.js: the open-source Augur (Aldrich et al. 2022)3 does dynamic taint tracking that follows JavaScript's asynchronous control flow.
- IAST: largely commercial (Contrast, Seeker), an agent that runs inside the app alongside a functional or DAST suite.
When to use, when not¶
Use:
- Web and service code with a clear untrusted-input surface — the static form belongs in CI as a security gate on every diff.
- Adding the dynamic form when a SAST tool's false-positive volume is unworkable and a functional or DAST suite is already exercising the code, so findings are confirmed against real execution.
Don't:
- Treat a clean run as proof. Implicit flows, and flows through a source or sink missing from the configuration, pass silently.
- Lean on the dynamic form for coverage: it only sees what the exercising traffic reaches, like any runtime observation.
Evidence¶
- On a package ecosystem. ODGen reported 180 previously unknown vulnerabilities in npm packages, 70 of which received CVE identifiers (Li et al. 2022)2.
Classification¶
- Quality dimensions: Security, Functionality.
- Area: Injection-class vulnerabilities — untrusted input reaching SQL, shell, eval, a file path, a URL fetcher, a deserializer; web and service code, security review of any language with a source→sink surface.
- Guarantee: Empirical.
Referenced by¶
- Agent security testing · Methods
- Deep static analysis · Methods
- Schema and boundary validation · Methods
- Static analysis · Methods
- Choosing methods · Overview
References¶
-
Sabelfeld, Andrei, and Andrew C. Myers. 2003. "Language-Based Information-Flow Security." IEEE Journal on Selected Areas in Communications 21 (1): 5–19. https://doi.org/10.1109/JSAC.2002.806121. ↩↩
-
Li, Song, Mingqing Kang, Jianwei Hou, and Yinzhi Cao. 2022. "Mining Node.js Vulnerabilities via Object Dependence Graph and Query." Proceedings of the 31st USENIX Security Symposium (USENIX Security 2022), 143–60. https://www.usenix.org/system/files/sec22summer_li-song.pdf. ↩↩
-
Aldrich, Mark W., Alexi Turcotte, Matthew Blanco, and Frank Tip. 2022. "Augur: Dynamic Taint Analysis for Asynchronous JavaScript." Proceedings of the 37th IEEE/ACM International Conference on Automated Software Engineering (ASE 2022), 153:1–4. https://doi.org/10.1145/3551349.3559522. ↩