Inside the Finalists: Seven Ways to Build a CRS

The seven AIxCC finalist systems shared an evidence contract but not an internal design. This comparison focuses on the responsibilities and boundaries that recurred across their systems—finding candidates, producing proofs, generating repairs, validating them, and preserving relationships—so the reader can judge what each architectural choice was trying to optimize rather than mistaking a long component list for capability.

The common contract created a useful constraint. Each team had to turn imperfect signals from real C and Java projects into evidence that could be submitted under time and accuracy rules. The teams were free to decide how much autonomy to give an agent, how much to rely on fuzzing or static analysis, whether to run many strategies in parallel, and how to coordinate the resulting state. Their differences are therefore not seven unrelated inventions. They are seven answers to the same systems question: where should uncertainty be handled, and which parts of the chain should be diverse, deterministic, or tightly controlled?

One evidence contract, several internal loops

At the discovery end, the finalists converged on two complementary pipelines. The first extended conventional fuzzing. Fuzzers generate many inputs, execute them against instrumented programs, observe coverage or abnormal behavior, and retain promising inputs for further mutation. That approach is strong at exploring behavior at scale, but it can stall when an input must obey a complicated grammar or satisfy a constraint that random mutation is unlikely to discover.

The teams addressed those barriers in different ways. They reused seed corpora collected from public sources, paired seeds with harnesses, and used language models to generate bootstrap inputs or troubleshoot coverage blockers. Some refined fuzzer feedback, schedulers, sanitizers, or dictionaries. Others explored grammar-based generation, directed fuzzing, concolic execution, or additional fuzzing engines. The point was not to make the fuzzer “understand” source code in the human sense. It was to give the search process better starting material and better guidance when ordinary mutation stopped making progress.

The second pipeline used language models more directly to identify bug candidates and generate proofs of vulnerability. Several teams combined static-analysis tools, sink lists, and LLM judgments to filter candidates before asking an agent to construct an input. The agent could receive source code, call paths, coverage, runtime logs, debugger access, and weakness-specific guidance. Some systems split the task into a reach phase, which tries to execute the relevant code, and an exploit phase, which tries to satisfy the condition that triggers the flaw.

These pipelines were not treated as competitors inside every CRS. Fuzzing could provide coverage information and near-solutions to a reasoning agent. A language-model generator could produce scripts, grammars, or failed attempts that became seeds for fuzzing. Even a failed generated input could be informative if it reached farther into the target than the fuzzer had managed. In the other direction, a fuzzer’s observation of a path or frontier could tell an agent where its next input should go. The exchange turned partial progress into a shared artifact rather than discarding it as a failed attempt.

That cooperation introduced a state-management problem. A CRS had to decide which inputs were novel, which crashes were duplicates, which candidate reports described the same bug, and which artifacts were ready to submit. Teams used stack traces, sanitizer signatures, input hashes, crash classifiers, or semantic grouping to make those decisions. A coarse rule could collapse distinct vulnerabilities; a permissive rule could flood the patching and submission stages with redundant work. Deduplication was thus part of the analysis logic because it changed what the system believed it had found.

The patching side followed a similarly recognizable loop:

classDiagram class Discovery class Fuzzing class LLMReasoning class EvidenceStore class PatchPipeline class RootCauseAnalysis class Validation class ReportAssembly Discovery <|-- Fuzzing Discovery <|-- LLMReasoning Fuzzing --> EvidenceStore : seeds, coverage, PoVs LLMReasoning --> EvidenceStore : candidates and PoVs EvidenceStore --> RootCauseAnalysis : runtime evidence RootCauseAnalysis --> PatchPipeline : repair hypothesis PatchPipeline --> Validation : candidate patch Validation --> EvidenceStore : accepted or failed evidence EvidenceStore --> ReportAssembly : linked artifacts

The loop began with optional root-cause analysis, moved to patch generation, validated the candidate, deduplicated related results, and submitted a selected patch. Root-cause analysis separated the question “what caused this behavior?” from the question “what edit should be made?” Some systems analyzed multiple PoVs to identify the common cause. Generation agents searched code and used crash reports, sanitizer output, project tests, or dynamic observations as context. Validation normally included building the project, replaying one or more PoVs, and running tests. Some teams added an LLM judge, post-patch fuzzing, or cached rebuilds.

The final stages were not passive quality checks. A patch that passed a single triggering input could still leave another PoV active. A patch that removed the crash could alter normal behavior. A patch generated for each PoV could duplicate an edit that fixed the same root cause. Teams therefore calculated minimal patch sets or expanded validation before submission. Those choices traded speed against confidence: using more evidence took time, but using too little increased the chance that a superficially successful fix would be submitted.

The same pattern appeared in SARIF assessment and bundling. A system could decide whether an alert was valid by matching it to a PoV, consulting its bug-candidate state, or asking an LLM to judge it. It could link a PoV, patch, and SARIF report when the relationship was supported by the system’s own analysis. The interface between these stages was the evidence store: it carried artifacts and their identities forward. If the store preserved only files without their meaning, later agents would have to reconstruct relationships and could introduce errors that were not present at discovery time.

Seven design bets, seven ways to place uncertainty

ATLANTIS chose an ensemble-first design. It combined independent bug-finding modules and a broad set of patching agents, including eight patching agents with different styles. The underlying bet was that no single method would be reliable across all targets and vulnerability classes. Diversity could supply robustness when one approach stalled, but it also created orchestration and deduplication costs. The system needed to share useful seeds and findings without letting parallel work overwhelm its resources or produce conflicting submissions.

BUTTERCUP placed more weight on expertise-driven decomposition. Its designers broke the work into well-defined subtasks and used LLMs where traditional tools were less effective. This approach treated problem definition as an engineering advantage: if a task can be bounded clearly, a mid-tier model paired with the right tool may be preferable to a more autonomous, less predictable agent. The trade-off is that the decomposition must anticipate the ways a real project can violate its assumptions. A workflow that is precise in the common case can become brittle when an unfamiliar build or input format crosses its boundaries.

ROBO DUCK made bug candidates the organizing object. Identification, filtering, proof generation, patching, SARIF validation, and bundling all revolved around candidate state. This is an agentic-first choice: instead of treating the CRS as a fixed chain of tools, it lets an agent decide which candidate to pursue and what evidence to request. The advantage is flexibility across different signals. The cost is that candidate state becomes a critical coordination point. If the system ranks or classifies a candidate incorrectly, later autonomy can amplify the original mistake through PoV generation, patching, and reporting.

FUZZING BRAIN pursued strategy diversity with a comparatively simple architecture. It implemented 23 independent strategies spanning full scans, delta scans, and SARIF-related work, varying their prompts, context, and language-model configurations. This design seeks breadth through many relatively separate attempts rather than a large central planner. It can expose useful variation under limited engineering effort, but it shifts the burden to strategy selection, resource allocation, and filtering. Independent attempts are valuable only if the system can recognize which outputs deserve to continue.

ARTIPHISHELL pursued the broadest technical coverage, with 53 components coordinated through a custom orchestration platform. That breadth allowed the system to combine many forms of discovery, reasoning, and patching. It also increased the number of interfaces, processes, and failure paths that had to remain coherent during autonomous operation. A broad architecture can contain more ways to solve a case and more ways for state, resources, or timing to go wrong. The design makes orchestration itself a central security function.

BUG BUSTER took a pragmatic route, emphasizing traditional fuzzing and program analysis while limiting LLMs to auxiliary roles such as seed generation. This is not an anti-LLM position; it assigns the model a narrower responsibility where the team judged it most useful and keeps more of the core behavior in established analysis techniques. The resulting system may be easier to reason about in those portions, but it gives up some of the direct code reasoning that helped other teams reach targeted or constraint-heavy cases.

LACROSSE used a multi-LLM workflow coordinated by a Lisp-based task distributor and DSPy. Its design treated model diversity, escalation, and fallback as workflow concerns. Different models could handle different stages or serve as alternatives when one attempt failed. That flexibility can improve coverage across task types, but it adds another dimension of scheduling and cost control. A multi-model system must decide not only which analysis to run, but when the expected value of another model call justifies the remaining budget and time.

The comparison reveals a shared set of design dimensions. Teams differed in how much they trusted autonomous agent loops, how much they decomposed work into deterministic subtasks, how widely they explored independent strategies, and how centrally they orchestrated components. They also differed in where they placed evidence filtering: before proof generation, during candidate pursuit, after multiple patches, or at submission. No choice dominates in the abstract. An ensemble needs reliability and selection; decomposition needs coverage of exceptions; agentic flexibility needs state discipline; simplicity needs enough technique coverage; and multi-model routing needs budget awareness.

This is why component count is a poor proxy for capability. A system with 53 components is not automatically stronger than one with 23 strategies or a simpler fuzzer-centered design. More components increase potential coverage only if the system can schedule them, share their useful state, isolate failures, and turn their outputs into accurate submissions. Conversely, a small architecture can be effective when its boundaries are clear and its strategy is well matched to the targets. The SoK taxonomy describes what the teams implemented, but it does not provide a controlled experiment showing which individual component caused which result.

The architecture also explains why validation, deduplication, and bundling belong in the center of a CRS. A discovery module does not hand a finished security result to a maintainer. It hands an uncertain candidate to the next stage. Each boundary must preserve enough context for the next decision and reject evidence that no longer meets the required condition. The system’s intelligence is therefore distributed across analysis, memory, scheduling, checking, and submission policy.

A useful comparison of the finalists should ask four questions. Where does the design obtain new evidence? Who owns the decision to pursue or discard a candidate? Which stage verifies that a proposed repair addresses the underlying behavior? And how does the system prevent parallel exploration from turning into duplicate or inaccurate output? Those questions connect local design choices to the system-level result.

The finalists answered them differently, but their common pattern is already clear: AIxCC did not produce one canonical CRS architecture. It produced a field of trade-offs around a shared evidence pipeline. The next interpretive step is to connect that pipeline to the scoreboard. A technique can be present in the code and still fail to appear in the result if the surrounding system cannot keep operating, preserve state, or submit accurately.

References