· 6 min read ·

How Constraint Reasoning Addresses the False Positive Problem That SAST Created

Source: openai

The false positive problem in security tooling is documented well enough that most teams have built institutional workarounds for it: rotating triage responsibility, setting severity thresholds to suppress low-confidence findings, or quietly deprioritizing SAST output altogether. OpenAI’s March 16 writeup on Codex Security frames the decision to move away from traditional SAST as an architectural choice rather than a workaround, and the reasoning is worth tracing through carefully.

How SAST Actually Works

Static Application Security Testing tools share a common model. They parse source code into an intermediate representation, define sources of attacker-controlled input (HTTP parameters, form fields, environment variables), define dangerous sinks (SQL execution, shell invocation, file writes, HTML rendering), and trace data flow between them. A finding is raised when tainted data reaches a dangerous sink without passing through a recognized sanitizer.

Semgrep operates mostly at the syntactic layer: you write patterns in a YAML-based DSL that describe code structures to flag. CodeQL, which GitHub acquired with Semmle in 2019, is more sophisticated. It compiles your codebase into a relational database and lets you express security queries in a Datalog-style language:

import python
import semmle.python.security.dataflow.SqlInjection

from SqlInjection::Configuration cfg,
     DataFlow::PathNode source,
     DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink,
  "SQL injection from $@.", source.getNode(), "user-controlled input"

CodeQL tracks data flow interprocedurally, reasons about method dispatch across file boundaries, and handles aliasing scenarios that purely syntactic tools miss. GitHub’s integration of CodeQL into its advisory and scanning infrastructure made it the most widely deployed sophisticated SAST in the industry.

False positive rates stay elevated anyway. Studies of industrial SAST deployments consistently report that engineers reject 40 to 70 percent of findings as non-actionable. The problem isn’t calibration, and better rules don’t fix it. It’s structural, embedded in the model itself.

The Structural Problem: Identification Without Validation

SAST tools are designed to be sound, or close to it. To avoid missing real vulnerabilities, they over-approximate: they assume any execution path the code allows might actually be taken. This means flagging vulnerabilities on paths that are unreachable at runtime, on data that is theoretically attacker-controlled but sanitized by functions the tool doesn’t model, and on patterns that structurally resemble vulnerabilities but depend on invariants the tool can’t verify.

The result is a finding that is technically correct about the flow while being wrong about the risk. The tainted data does reach the sink, but only after passing through an authentication check, a role authorization gate, and an input coercion that makes exploitation infeasible. SAST sees the flow. It cannot see the constraints that bound it.

Most false positives originate in this gap between “does this code contain a potentially dangerous pattern” and “can an attacker exploit this in practice.” Closing that gap requires reasoning about the program’s invariants, not just its data flows.

Constraint Reasoning as a Different Paradigm

The approach Codex Security uses, AI-driven constraint reasoning, addresses a different question from the start. Rather than enumerating source-to-sink paths, it builds a model of the constraints the program enforces, including authentication requirements, type invariants, input length bounds, and encoding transformations, and then evaluates whether an attacker can satisfy the conditions necessary to reach a dangerous state.

This is structurally closer to how symbolic execution tools like KLEE reason about programs. KLEE represents program inputs as symbolic variables and maintains the path conditions that must hold for execution to follow each branch. Finding a vulnerability becomes a constraint satisfaction problem: is there a concrete input assignment that satisfies the path conditions to reach the dangerous state?

# Simplified symbolic path condition reasoning
# Branch: if user.role == "admin": allow_access(query)
#
# Symbolic execution tracks:
#   path_cond: symbolic_user.role == "admin"
#
# If attacker controls user.role freely => SAT => potentially exploitable
# If user.role is always assigned from a fixed authenticated session object
#   with no attacker-observable write path => UNSAT => not exploitable
#
# SAST raises a finding in both cases.
# Constraint reasoning distinguishes them.

Angr, the binary analysis framework, implements concolic execution and state merging as practical mitigations to the scaling challenges of full symbolic execution. But the fundamental problem with exhaustive state exploration, path explosion, where the number of reachable states grows combinatorially with branch complexity, doesn’t disappear through engineering. KLEE’s own documentation acknowledges that even moderately complex programs require careful search strategy tuning to get useful results.

AI-driven constraint reasoning sidesteps exhaustive exploration by working probabilistically. A learned model assesses which constraints are actually enforced and whether they’re bypassable, without exploring every possible execution path. The trade-off is soundness for scalability: the tool cannot guarantee it finds every vulnerability, but it can focus analysis on cases where exploitation is plausible rather than merely theoretically possible.

The Validation Step Changes the Cost Structure

The second component of the Codex Security approach is automated validation: after identifying a potential vulnerability, attempting to demonstrate actual exploitability rather than handing a hypothesis to a human engineer.

This is the step that traditional SAST skips entirely. Every SAST finding is a hypothesis. The work of validating that hypothesis, tracing the execution path manually, verifying that sanitizers in the path don’t actually block the exploit, constructing a proof of concept, often takes more engineering time than fixing the vulnerability itself would have. High false positive rates translate directly into hours spent on non-issues.

Automated validation changes this by making the tool responsible for the triage work it would otherwise offload. If a tool produces a working proof of concept alongside a finding, or a structured argument for why the vulnerability is exploitable under specific conditions, the human triage burden drops significantly. Findings that cannot be validated are not raised.

OSS-Fuzz’s AI-guided fuzzing components pursue a related goal from a different direction: using language models to guide input generation toward interesting program states, bridging the gap between “this execution path exists” and “here is an input that exercises it.” The underlying insight is the same; demonstrating exploitability is a more useful output than identifying potential paths.

Where This Sits in the Broader Ecosystem

The direction of travel across security tooling has been consistent. Semgrep has added AI-assisted triage to help developers understand and prioritize findings. Meta’s CyberSecEval benchmark suite has been mapping LLM security capabilities systematically since 2024, establishing where language models perform reliably and where they don’t. Google’s Project Zero has published research on LLM-assisted vulnerability research, particularly for variant analysis of known vulnerability classes.

What distinguishes the Codex Security architecture is that the AI reasoning is the primary detection mechanism rather than a layer on top of SAST findings. The constraint reasoning and validation aren’t post-processing outputs from a traditional analyzer; they are the analysis. That means the false positive problem is addressed at the source rather than filtered downstream.

The coverage question is harder to evaluate externally. Rule-based SAST tools with comprehensive rule sets have known, auditable coverage for specific vulnerability classes. An AI-driven approach can generalize to novel patterns, but reliability on vulnerability classes that require subtle semantic reasoning, or on attack patterns without training analogs, is harder to characterize without benchmarking against something like the NIST SARD test suite or curated CVE datasets. The Juliet Test Suite, which covers around 100 CWE categories, provides one starting point for evaluating this, though its synthetic nature limits conclusions about real-world performance.

The Trade-off Worth Being Clear About

Reducing false positives through automated validation has a cost in false negatives. A tool that only reports findings it can validate will miss vulnerabilities where its validation model fails or where the constraint reasoning produces an incorrect unsatisfiable result. Whether that trade-off is acceptable depends on the deployment context. For teams where SAST noise has led engineers to broadly discount security findings, a tool with fewer but higher-confidence outputs can produce better security outcomes even with lower raw coverage, because the findings it does raise get treated seriously and fixed. For security audits where completeness is the primary requirement, the risk calculus looks different.

The SAST market has always calibrated between sensitivity and specificity. Every tool makes a choice about where on that axis to operate. What AI-driven constraint reasoning changes is where that calibration happens: not in hand-tuned rules or static thresholds, but in a learned model of what exploitability looks like in context. That shifts the complexity from rule maintenance to model quality, which carries its own maintenance challenges. It also means the tool’s judgment about exploitability can improve over time as the model is refined against confirmed vulnerability patterns, which is a property that no static rule set shares.

Was this interesting?