Why OpenAI's Codex Security Doesn't Rely on SAST Reports

OpenAI explains why Codex Security was intentionally designed to analyze repositories from the code and system intent rather than starting from SAST reports, since the most critical vulnerabilities involve defenses that appear correct but fail to enforce the properties the system depends on.

openai Mar 16, 2026

Static application security testing (SAST) has long been a primary method for security teams to scale code review. However, when building Codex Security, OpenAI made a deliberate design decision: rather than importing a static analysis report and having the agent triage it, the system begins with the repository itself-examining its architecture, trust boundaries, and intended behavior-and validates discoveries before surfacing them to a human.

The rationale is straightforward: the most critical vulnerabilities typically aren't simple dataflow problems. They occur when code appears to enforce a security check that doesn't actually guarantee the property the system depends on. The challenge goes beyond tracking data movement through a program-it requires determining whether the defenses in the code truly work.

SAST Is Built Around Dataflow

SAST is commonly described as a clean pipeline: identify an untrusted input source, trace data through the program, and flag cases where it reaches a sensitive sink without sanitization. It's an elegant model covering many real bugs.

In practice, SAST must make approximations to remain tractable at scale-particularly in codebases with indirection, dynamic dispatch, callbacks, reflection, and framework-heavy control flow. These approximations are an inherent reality of reasoning about code without executing it.

However, that alone isn't the reason OpenAI's Codex Security avoids starting with a SAST report. The deeper issue concerns what happens after a source-to-sink trace is successfully completed.

Where Static Analysis Falls Short: Constraints and Semantics

Even when static analysis correctly traces input across multiple functions and layers, it still must answer the question that truly determines whether a vulnerability exists: did the defense actually work?

Consider a common pattern: code invokes something like sanitize_html() before rendering untrusted content. A static analyzer can confirm the sanitizer ran, but it typically cannot determine whether that sanitizer is sufficient for the specific rendering context, template engine, encoding behavior, and downstream transformations involved.

There is a significant difference between "the code calls a sanitizer" and "the system is safe."

Illustrative Example: Validation Before Decoding

A pattern frequently encountered in real systems involves a web application receiving a JSON payload, extracting a redirect_url, validating it against an allowlist regex, URL-decoding it, and passing the result to a redirect handler.

A typical source-to-sink report describes the flow:

untrusted input → regex check → URL decode → redirect

The real question isn't whether a check exists-it's whether that check still constrains the value after the transformations that follow. If the regex runs before decoding, does it actually constrain the decoded URL as the redirect handler interprets it?

Answering this requires reasoning about the entire transformation chain: what the regex permits, how decoding and normalization behave, how URL parsing handles edge cases, and how redirect logic resolves schemes and authorities.

Many significant vulnerabilities follow this pattern: order-of-operations mistakes, partial normalization, parsing ambiguities, and mismatches between validation and interpretation. The dataflow is visible, but the weakness lies in how constraints propagate-or fail to propagate-through the transformation chain.

This isn't merely theoretical. In CVE-2024-29041, Express was affected by an open redirect issue where malformed URLs could bypass common allowlist implementations due to how redirect targets were encoded and then interpreted. The dataflow was straightforward; the harder question was whether validation still held after the transformation chain.

OpenAI's Approach: Start from Behavior, Then Validate

Codex Security is designed around a core goal: reducing triage by surfacing issues with stronger evidence. In practice, this means leveraging repo-specific context (including a threat model) and validating high-signal issues in an isolated environment before presenting them.

When Codex Security encounters a boundary that looks like "validation" or "sanitization," it doesn't treat it as a checkbox. Instead, it tries to understand what the code is attempting to guarantee-and then attempts to falsify that guarantee.

This typically involves a combination of:

  • Reading the relevant code path with full repository context, as a security researcher would, looking for mismatches between intent and implementation. This includes comments, though the model doesn't blindly trust them-adding //Halvar says: this is not a bug above code won't confuse it if a real bug exists.
  • Reducing the problem to the smallest testable slice (for example, the transformation pipeline around a single input) to enable focused reasoning. Codex Security extracts small code slices and writes micro-fuzzers for them.
  • Reasoning about constraints across transformations rather than treating each check independently. Where appropriate, this can include formalization as a satisfiability question-the model has access to a Python environment with z3-solver and uses it effectively when needed, much as a human would for complicated input constraint problems. This proves especially useful for examining integer overflows or similar bugs on non-standard architectures.
  • Executing hypotheses in a sandboxed validation environment when possible, distinguishing "this could be a problem" from "this is a problem." A full end-to-end proof-of-concept with the code compiled in debug mode provides the strongest evidence.

The key shift is that instead of stopping at "a check exists," the system pushes toward "the invariant holds (or it doesn't), and here's the evidence." The model selects the best tool for each situation.

Reasons for Not Seeding Codex Security with a SAST Report

A natural question is: why not combine both approaches? Start with a SAST report, then have the agent reason more deeply.

Precomputed findings can help in some cases-especially for narrow, known bug classes. But for an agent designed to discover and validate vulnerabilities in context, beginning from a SAST report creates three predictable failure modes.

First, it can encourage premature narrowing. A findings list represents where a tool already looked. Treating it as the starting point can bias the system toward spending disproportionate effort in the same regions, using the same abstractions, and missing issue classes that don't fit the tool's perspective.

Second, it can introduce implicit judgments that are difficult to unwind. Many SAST findings encode assumptions about sanitization, validation, or trust boundaries. If those assumptions are wrong-or incomplete-feeding them into the reasoning loop can shift the agent from "investigate" to "confirm or dismiss," which isn't the intended behavior.

Third, it can make evaluating the reasoning system harder. If the pipeline starts with SAST output, separating what the agent discovered through its own analysis from what it inherited from another tool becomes difficult. That separation matters for accurately measuring the system's capabilities, which is essential for ongoing improvement.

OpenAI built Codex Security to begin where security research begins: from the code and the system's intent, using validation to raise the confidence bar before interrupting a human.

SAST Tools Remain Valuable

SAST tools excel at their intended purpose: enforcing secure coding standards, catching straightforward source-to-sink issues, and detecting known patterns at scale with predictable tradeoffs. They serve as a strong component of defense-in-depth.

The point here is narrower: an agent designed to reason about behavior and validate findings should not begin its work anchored to a static findings list.

It's also worth noting a related limitation of pure source-to-sink thinking: not every vulnerability is a dataflow problem. Many real failures involve state and invariant issues-workflow bypasses, authorization gaps, and "the system is in the wrong state" bugs. For these, no tainted value reaches a single "dangerous sink." The risk lies in what the program assumes will always be true.

Future Directions

OpenAI expects the security tooling ecosystem to continue improving: static analysis, fuzzing, runtime guards, and agentic workflows will all play roles.

The goal for Codex Security is to excel at the part that costs security teams the most: turning "this looks suspicious" into "this is real, here's how it fails, and here's a fix that matches system intent."

For more details about how Codex Security scans repositories, validates findings, and proposes fixes, see OpenAI's documentation.