Why Generic AI Agents Fail at Security

Most AI security demos focus on a single repository or a curated benchmark. In reality, enterprise codebases span dozens of languages, thousands of dependencies, and millions of lines of code. A single-agent approach hits three fundamental walls:

  1. Context exhaustion — After an hour, the context window fills up and the model forgets bugs it found earlier.
  2. Single hypothesis — Agents explore one attack path at a time, missing the bigger picture.
  3. No persistence — A crash or timeout loses all progress.

Cloudflare's journey started with a 450-line security audit skill that ran on one repo. It worked, but a single run found only about half the bugs. The solution wasn't a better model — it was a model-agnostic orchestration layer that treats LLMs as interchangeable compute engines.

Source: Cloudflare Blog

Cloudflare vulnerability discovery harness architecture diagram showing pipeline stages IT Technology Image

Architecture: The Two-Stage Pipeline

Cloudflare's system splits vulnerability management into two independent stages, each using a different model:

Stage 1: Vulnerability Discovery Harness (VDH)

AgentRoleDetails
ReconMaps architecture & threat vectors3 parallel agents write architecture.md
HuntPer-class attacksSpawns sibling agents, uses sandboxed binaries
ValidateMechanical check + adversarial disprovalTwo-pass: schema check, then agent tries to disprove
GapfillGenerates new tasks for uncovered areasEnqueues fresh hunts for empty coverage cells
DedupConsolidates overlapping findingsClusters by root cause
TraceWalks dependency graphSpawns consumer-repo tasks
FeedbackLearns from past runsRewrites prompts based on validation failures
ReportRenders human-readable outputNo model required

Stage 2: Vulnerability Validation System (VVS)

AgentRoleDetails
DedupIdentifies duplicates across all sourcesDeterministic index + probabilistic reasoning
JudgmentProduction reachability & risk scoringPulls from MCP, Jira, git, config
FixerGenerates patches + runs regression testsRequires clean fail→pass flip; never merges without human
# Simplified example: orchestrating stages with a database backend
import sqlite3
from enum import Enum

class Stage(Enum):
    RECON = "recon"
    HUNT = "hunt"
    VALIDATE = "validate"

class Harness:
    def __init__(self, db_path: str):
        self.conn = sqlite3.connect(db_path)
        self.conn.execute("""
            CREATE TABLE IF NOT EXISTS findings (
                run_id TEXT,
                repo TEXT,
                stage TEXT,
                data TEXT,
                status TEXT DEFAULT 'pending'
            )
        """)
    
    def run_stage(self, run_id: str, repo: str, stage: Stage, task: callable):
        # Check if already completed
        cursor = self.conn.execute(
            "SELECT status FROM findings WHERE run_id=? AND repo=? AND stage=?",
            (run_id, repo, stage.value)
        )
        row = cursor.fetchone()
        if row and row[0] == 'completed':
            return
        
        result = task()
        self.conn.execute(
            "INSERT OR REPLACE INTO findings VALUES (?,?,?,?,?)",
            (run_id, repo, stage.value, result, 'completed')
        )
        self.conn.commit()

Developer monitoring AI-powered security pipeline dashboard with real-time findings

Critical Lessons from Production

1. Persistence Before Parallelism

Every stage writes to a SQLite database keyed by (run_id, repo, stage). Findings are streamed and saved as they happen — a crash costs you only the task in flight. This is non-negotiable for runs that can take 14+ hours.

2. Watch for Silent API Errors

Sometimes a transient API error comes back as text in a 200 OK response instead of throwing an exception. You must explicitly classify the response text, not just trust the status code.

3. Sandboxing Needs Careful Configuration

If your harness runs inside Docker, the sandbox (used to crash binaries) needs seccomp=unconfined and apparmor=unconfined or it will silently fail to start.

4. Don't Wire in Static Analysis Early

Cloudflare plumbed Semgrep through the entire pipeline. In a month of runs, Hunters invoked it zero times. They preferred to read and run the code. The most-used tool? A central wishlist where agents request resources.

5. Deduplication is Its Own Problem

At scale, comparing findings with simple string matching fails. Cloudflare uses deterministic code to build inverted indexes over files, functions, and rare tokens, then only uses an LLM to reason over a short candidate list.

6. Forge Adversarial Verification

Every finding must include:

  • A stated threat model (who is the attacker, what boundary is crossed)
  • A PoC that runs against the original, untouched codebase
  • A proposed patch

A separate Validator (which cannot file its own findings) tries to disprove everything. If a Hunter grades its own homework, it will confidently validate nonsense.

Explore the open-source skill that started it all.

Multi-model security scanning infrastructure abstract illustration with interconnected nodes

Real-World Metrics & Limitations

For a standard ~30k LOC repository:

  • Initial findings: ~100 raw candidates
  • After validation: ~80 high-fidelity bugs
  • Time to fix with human review: ~14 hours for the pipeline, then 5 days for critical fixes, 15-20 days for hardening
  • Lifetime compression: ~65% reduction in candidates across the fleet

Limitations & Caveats

  • No false-negative rate: There's no labeled set of every real bug in a codebase. The team measures effectiveness by tracking whether re-runs keep finding new bugs.
  • Cost is hunt-stage heavy: Budget per repo, not per run. Use a task cap and worker pool (50-200 workers) to avoid wasting compute.
  • Not for per-PR checks: Full scans take hours. Use cheaper, smaller harnesses for CI.
  • Human-in-the-loop is mandatory: The Fixer never merges without a human signing off on a dry run.

Next Steps

  1. Start with a single-repo skill in your dev environment. Get prompts working well before building infrastructure.
  2. Add persistence (SQLite) before adding parallelism.
  3. Add a wishlist mechanism — let agents tell you what they need.
  4. Introduce adversarial verification with a separate model for validation.
  5. Only build cross-repo tracing when you have more than one repository that matters.

Further Reading

This content was drafted using AI tools based on reliable sources, and has been reviewed by our editorial team before publication. It is not intended to replace professional advice.