Security Lab
AppSec Practice by Nadav Czerninski

AI-Generated Code and AppSec: Runtime's Last Honest Signal

What happens to security review when code volume outruns reviewer throughput? A developer can use a code assistant to create a file upload handler and see it reach the repository within minutes. A review that would normally cover that function in a PR cycle set for Friday afternoon may now be chasing code already in staging on Tuesday. At many organizations adopting LLM-assisted development quickly, output has outpaced security review in practical terms. This is not a criticism of the tools, but an observation about the current AppSec process.

The models produce code that looks plausible. It compiles, passes unit tests, and meets the stated requirement. Yet it may mishandle attacker-controlled input. LLMs most often reproduce patterns found frequently in their training data, including decades of Stack Overflow answers and tutorials that focused on making examples work rather than making them safe.

The Vulnerability Patterns Most Common in Generated Code

Across the services we instrument, some vulnerability classes recur in AI-assisted code. None are new. They are familiar flaws that models replicate because insecure patterns occur frequently in the training corpus.

Path traversal is among the most common. A generated file handler that builds a path from user input and then opens it often looks like this:

# Common pattern from generated code -- path traversal risk
@app.route('/files/<filename>')
def serve_file(filename):
    return send_from_directory('/data/uploads', filename)

send_from_directory offers some protection, but generated examples frequently replicate the pattern of taking a filename from a URL parameter and passing it straight to a file operation through lower-level constructs without that protection. The safe pattern uses os.path.abspath and confirms that the resolved path begins with the intended directory prefix. Models produce both forms, yet the vulnerable one appears in the training corpus and is reproduced.

Command injection through subprocess or os.system with unsanitized user input is another recurring pattern. Code generated to "run a command based on the user's input" often uses shell=True with string concatenation instead of argument arrays. Generated utility code also contains deserialization of untrusted data through pickle or yaml.load (without Loader=yaml.SafeLoader). Each pattern is documented as dangerous, but the models learned from examples that predate or disregard that guidance.

Why Static Analysis Falls Short on AI-Generated Output

SAST tools assess generated code as they do human-written code. The issue is not the tool but coverage. SAST has a well-understood false negative rate for human-written codebases. AI-generated code carries the same rate, but its greater volume means the absolute number of missed issues rises proportionally.

More precisely, SAST detects patterns in static code, but cannot tell whether a vulnerable path is reachable under real production traffic. A generated function with a SQL injection pattern may never receive external user input in the application's actual architecture. SAST flags it anyway, consuming team time on a finding that was never exploitable. Conversely, SAST may miss a finding in a context it does not trace. Either way, code alone cannot reveal the ground truth of what is happening in production.

Runtime as Ground Truth

Runtime instrumentation records what executing code does with actual inputs. A path traversal flaw present in source but never reached by real traffic remains invisible to runtime detection and creates no noise. When a traversal attempt reaches the vulnerable path in production, runtime produces a specific kernel-level signature: a file open syscall whose path resolves outside the expected directory prefix.

This does not replace SAST; it provides a different signal. SAST shows what could go wrong in code, while runtime shows what is actually happening. The combined approach is to run SAST on AI-generated code before deployment, accepting false positives as the cost of not missing issues, then instrument runtime to see which patterns appear under production traffic.

The runtime signal is more candid than code analysis. Code may appear safe yet be exploited through interaction patterns no one anticipated during writing or review. Runtime exposes those events.

How This Changes AppSec Process

The traditional AppSec model assumed code changed at a fairly stable rate, one security review could match when properly resourced. AI-assisted development breaks that assumption. The answer is not to resist AI-assisted development or require review capacity to grow at the same pace as code output. It is to recognize that pre-deployment review will cover less of the code surface than before, making runtime observation more important as a compensating control.

That means instrumenting production services earlier in the product lifecycle rather than treating it as an afterthought. It means giving anomalous runtime behavior the same standing as SAST findings. It also means creating response workflows that handle runtime alerts with the urgency applied to critical static-analysis findings.

We are not claiming AI-assisted development harms security. Models also produce security-correct code, and developer tools built around them are beginning to include security context in their suggestions. The point is that "LLM suggests it" is no security guarantee, and processes designed for code written entirely by humans must adapt when that is no longer the case.

What Runtime Cannot Reveal

Runtime observation covers code triggered in production. Vulnerabilities in paths receiving no real traffic remain unseen until a SAST tool or an attacker discovers them. For new features not yet carrying real load, pre-deployment SAST remains the right tool. Runtime complements SAST in production; it does not replace SAST in the development pipeline.

The candid conclusion is that no single layer is enough. The volume of AI-generated code entering production in 2025 brings more code, more possible vulnerabilities, faster release cycles, and a greater chance that exploitable code reaches production without a security-focused review. Runtime instrumentation observes what actually runs under real conditions, regardless of who wrote it or which tools reviewed it before deployment.

See runtime detection patterns in your clusters

Deploy Oligo's eBPF instrumentation and watch the runtime graph emerge for your workloads.

Request Access More Articles