SAST for the AI Era: Scanning Prompts, Agents, and LLM Glue Code
The code being written today looks different from the code most SAST rulesets were designed for. Applications now string together prompts, call language models, hand those models tools, and let agents act on the results. The good news is that taint analysis — the engine behind static analysis — transfers directly. The catch is that AI applications introduce new kinds of sources and sinks that a conventional ruleset has never heard of, and until you teach it, the scanner walks straight past them.
An LLM application is, from a data-flow perspective, a program with two unusual properties. Untrusted text can become instructions rather than mere data — prompt injection — and the model's output is itself untrusted, yet is routinely fed into code, queries, shells, and tool calls. Both properties map cleanly onto taint concepts; they just require declaring new sources and sinks the default rules omit.
New sinks: where prompt data does damage
- Untrusted input concatenated into a prompt. User text spliced directly into a system prompt is the AI-era analogue of string-built SQL — a classic injection sink, now pointed at a model.
- Model output reaching a dangerous operation. An LLM response passed to
eval, a shell, an SQL query, or a filesystem path is a sink fed by an untrusted source. - Tool and function invocation from model output. When an agent lets the model choose which tool to call with which arguments, unvalidated output drives real actions — excessive agency in code form.
New sources: the model is untrusted
The mental shift that trips teams up is treating the LLM's output as a taint source, not a trusted return value. A model can be manipulated by upstream content — a poisoned document in a retrieval store, a malicious web page an agent browses — so anything it emits must be validated before it reaches a sink, exactly as you would validate a request parameter. A custom rule that marks the model client's response as tainted and flags its flow into exec or a query surfaces a whole class of bugs the defaults miss.
os.system(resp.text) # sink: LLM output reaches a shell
Scanning the glue code
Most AI risk in a real codebase lives in the plumbing: the orchestration framework, the tool definitions, the agent loop, the retrieval wiring. Point custom rules at it. Flag hardcoded model API keys, tool definitions that pass model-chosen arguments to sensitive functions without validation, missing output-schema checks, and prompts assembled by naive string concatenation. These are static patterns a rule engine matches reliably — and they are the patterns generic rulesets, written before this architecture existed, do not carry.
Discovery is the harder half
Before any of this helps, you have to know the AI code exists. LLM features are often bolted on by individual teams — an SDK import here, an agent script there — outside the paths security reviews cover. Scanning for AI SDK imports, model-client calls, and prompt-construction patterns doubles as an inventory: it finds the AI surface area in your codebase, including the parts nobody told you about. Building that inventory of where models are wired into code is exactly the discovery problem Shadow AI Discovery was built to solve.
The engine has not changed; the map has. Teach your analyser the new sources and sinks, aim it at the glue, and the same data-flow discipline that has caught injection for two decades catches its AI-era descendants — but only across the code you have actually found. You cannot secure the model integration you never knew shipped.
- Check whether your SAST config treats model output as a taint source and prompt construction or tool invocation as sinks — default rulesets predate this architecture and walk straight past it.
- Grep for AI SDK imports and model-client calls to see where models are wired into your code; the risky integration is often the one nobody told security about.
A grep for SDK imports scratches the surface; discovering every place a model is wired into your code — the Shadow AI inventory — is what our assessment runs for you.