Curated security research, vulnerabilities, advisories and tools for practitioners.

From AI Agents to RCE - Building a Vulnerability Research Workflow

Summary

The edge isn't the AI model, but how you assemble the system around it. We built a custom agentic harness that structures vulnerability research into distinct stages, from codebase exploration and analysis to validation and exploitation. Applied to FreeRDP, the workflow found vulnerabilities that could be chained into remote code execution, with a human researcher validating the findings and guiding the process along the way.
Published
Collected

📦 Full-Text Content Snapshot

R2 Archive · Full Article Preserved221 lines · 16.0 KB
📄 Raw .md⬇️ Download .md

Author: Julien Lair · Published: September 29, 2026 · Source: blog.quarkslab.com

The edge isn't the AI model, but how you assemble the system around it. We built a custom agentic harness that structures vulnerability research into distinct stages, from codebase exploration and analysis to validation and exploitation. Applied to FreeRDP, the workflow found vulnerabilities that could be chained into remote code execution, with a human researcher validating findings and guiding the process along the way.


Introduction

A security researcher spends most of the day reading code. Thousands of lines, sometimes, just to find the few that matter. Most of that reading is not where the meaningful work happens. The real work is the moment of suspicion: this length field is validated here but not there, this state can be entered twice, this loop trusts a value it should not trust. That moment takes seconds. Reaching it can take days.

An agent can work across a codebase in minutes, connecting functions scattered across files and following relationships that would take a researcher much longer to piece together by hand. What is less clear is what comes out of that volume: real vulnerabilities, or a pile of false positives to sort through.

We wanted to turn this raw power into a method. We built an agent harness for vulnerability research: the surrounding system that manages the tools, context, structure, and rules AI agents need to work on a task. In our case, that means a queryable graph over the target, a deterministic analysis core, a set of lenses that read its output, and a staged pipeline the agents work through. The harness proposes attack vectors, explores the code paths involved, and writes proofs of concept, with a researcher checking every step that matters.

The goal was not a push-button vulnerability finder, but a methodology that can be run, inspected, and repeated: the agents handle the groundwork, correlate what they find, and bring up leads, while the researcher validates them, directs the investigation, and decides what deserves more time. What we were really after was a researcher who spends the day suspecting rather than scrolling.

This article follows the workflow from the first pass over a codebase to a working exploit, showing the output of each stage along the way. We tested it on FreeRDP, an open-source RDP client, a large target, where it uncovered two vulnerabilities that can be chained into remote code execution on the client.

The Problem, and What We Did About It

Late in December 2025, one person targeted nine Mexican government agencies. Not a crew, not a state program. Over the following seven weeks they typed 1,088 instructions, which produced 5,317 commands executed across 34 separate sessions. Claude Code handled around 75% of the live exploitation across 305 internal servers, while a second pipeline built on GPT-4.1 read the takings and tasked the next move. Close to 200 million records left the building: tax filings, the civil registry, patient data, vehicle records, the electoral roll. The forensics come from the attacker's own recovered servers.

The useful number here is the ratio: roughly five commands were executed for every instruction typed. A similar pattern appeared three months earlier in a China-linked campaign, where the model reportedly handled 80 to 90 percent of the tactical work against roughly thirty organisations.

For defenders, the important change is the amount of work one operator can sustain. The Mexico operation was run by one person, while automation covered tasks that would previously have required several skill sets. Defenders often assume that an attacker's skills set a ceiling on what they can do; agentic tooling weakens that assumption.

The campaign did not rely on novel exploitation techniques. Its significance was the scale at which one operator could carry out the work. That raises the defensive question behind this project: if automation can reduce the cost of exploiting known weaknesses at scale, can it also reduce the cost of finding and understanding new ones? We built the workflow to test that question, and pointed it at FreeRDP.

That same ability to produce work at scale creates a different problem for defenders: more output does not necessarily mean more useful findings. curl illustrates this well: its confirmed-vulnerability rate fell from above 15 percent of submissions to below 5 percent, with about one report in five during 2025 amounting to machine-generated noise, each still costing hours of a volunteer team's time. The programme eventually closed. The reports were costly because many were plausible: they cited real functions and code paths and described attack scenarios that required investigation before they could be dismissed.

The limiting resource is therefore researcher attention, not the number of findings a system can produce. We designed the workflow to search broadly, then spend machine time filtering and validating candidates before asking a researcher to inspect them.

What Already Exists, and Why We Built Our Own Anyway

Several existing systems address adjacent parts of this problem: Google's Big Sleep for AI-assisted vulnerability research, OpenAI's Aardvark (now Codex Security) for continuous security analysis of code repositories, and the autonomous systems developed for DARPA's AI Cyber Challenge (AIxCC).

Their results show that agent-assisted vulnerability research can work:

  • Big Sleep turned up a memory-corruption bug in SQLite that threat actors already knew about, and reported twenty more in projects such as FFmpeg and ImageMagick.
  • Aardvark builds a threat model from a repository, tests each commit against it, and validates what it finds in a sandbox.
  • AI Cyber Challenge systems were designed to find and patch vulnerabilities autonomously.

Each was built for a job adjacent to ours:

  • Aardvark watches a repository as you commit to it, which is the right instinct when the code is yours and no help at all when auditing third-party code you have never touched.
  • Big Sleep is an internal Google tool.
  • The AIxCC systems presume a fuzzing harness already exists and are scored on running unattended; the FreeRDP surface we cared about had no harness, and we had no intention of running unattended.

The deeper reason is simpler: a tool that decides everything by itself hands you a conclusion and nothing else. You then have to redo the work to find out whether it is true, which costs roughly what finding it would have cost. We had no intention of doing that with reports from our own tooling.

The Workflow, in One Picture

The architecture separates two properties we wanted to use differently: language models are useful for generating and exploring hypotheses, but their outputs are not reproducible (due to their non-deterministic nature).

The system therefore has two layers:

  1. A deterministic core: indexes the code into a queryable graph, runs static taint from attacker-controlled sources to dangerous sinks, and passes the result through a set of narrower lenses: known CVE and CWE patterns, and target-specific checks.
  2. An agent layer: forms hypotheses, reads what the core has surfaced, judges what is real, and drives it towards a PoC.

The core is tuned for recall rather than precision. It over-produces on purpose, because a lead never generated can never be recovered, and the agent layer exists to absorb the noise a broad search inevitably produces so that a researcher sees only what survived. The core is reproducible; the agent layer is auditable.

The pipeline runs in eight stages:

text
graph → recon → slicing → analysis → triage → poc → chain → exploit
StageWhat it does
graphIndexes the codebase.
reconTurns structure into attack surface.
slicingNarrows things to a single hypothesis — no agent reasons well across an entire repository.
analysisRuns taint, pattern matching and the other lenses over that slice.
triageSorts the output into real, unclear and noise.
pocAttempts to make a survivor fire.
chainAsks whether two weak primitives amount to one strong one.
exploitTurns a validated primitive or chain into a working exploit.
The eight-stage workflow
The eight-stage workflow

The researcher works between the stages, never inside them. They can enter at any step: run the whole pipeline end-to-end, stop after recon, or hand the pipeline a finding of their own to automate triage and poc.

Applying the Workflow to FreeRDP

We pointed the workflow at the FreeRDP tree at commit 993499447 with no prior CVE list, no fuzzing corpus, and no hints. FreeRDP is the library underlying Remmina, GNOME Connections, KRDC, and Apache Guacamole guacd. We audited the client, where every byte parsed from the network originates from a server the user chose to trust.

Step 1 — Graph, Recon and Slicing

Graph indexed the target into a queryable representation: 13,506 functions, 3,105 types, and 31,705 call edges (including resolved function pointers).

nego.c resolved in the graph
nego.c resolved in the graph

Reachability queries turn an entry point into a working set:

bash
$ sift graph reachable nego_recv --files
libfreerdp/core/nego.c
libfreerdp/core/tpdu.c
libfreerdp/core/tpkt.c
… 6 more

Recon estimates exposure, producing a threat model and ordered slices.

Components by exposure
Components by exposure

The run produced 304 slices. The two findings came from slice 166 (libfreerdp/core/nego) and slice 109 (channels/urbdrc/client/data_transfer).

Step 2 — Analysis

The deterministic core runs static taint and pattern lenses. In slice 166, the engine produced 14 findings. Two became interesting together:

text
f-007  attacker-controlled length stored in nego->RoutingTokenLength
                         ↕ ?
f-005  same field later used as a Stream_Write size

The engine reported them separately rather than guessing a relationship across the lifetime of the nego object.

Findings f-005 and f-007 combined
Findings f-005 and f-007 combined

Slice 109 produced 116 findings. Two pointed to a USB-redirection completion path where an error leaves an attacker-supplied OutputBufferSize in place even though no data has been written, leaking uninitialized heap bytes back to the server.

Step 3 — Triage and PoC

Triage grouped the 130 findings into 36 clusters: 20 real and reachable, 3 latent, 3 mixed, and 10 false positives.

For slice 166, the pipeline connected f-007 and f-005. While the primary negotiation request path enforced protocol bounds, the Server Redirection PDU path (where LoadBalanceInfo is reused as a routing token on reconnection) had no length restriction.

Tested against an ASan-instrumented FreeRDP client, a malicious server sending a 600-byte LoadBalanceInfo triggered an out-of-bounds heap write:

text
==4514==ERROR: AddressSanitizer: heap-buffer-overflow
WRITE of size 615

#2  Stream_Write
#4  nego_send_negotiation_request  libfreerdp/core/nego.c:1098
#9  rdp_client_redirect            libfreerdp/core/connection.c:715

0x75e976227180 is located 0 bytes after 512-byte region
[0x75e976226f80,0x75e976227180) allocated by thread T2 here:

#1  Stream_New
#2  nego_send_negotiation_request  libfreerdp/core/nego.c:1083

In slice 109 (USB redirection), the uninitialized heap disclosure was confirmed with ASan poison pattern 0xcd:

text
[poc] heap pattern bytes (0xcd) in region [36..100): 64 / 64

Step 4 — Chaining

The negotiation bug provided an attacker-controlled blind heap overflow write, while the USB redirection bug provided heap disclosure. The information leak operates post-authentication; server redirection then forces a reconnect to trigger the controlled overflow.

Step 5 — Exploitation

We structured exploitation with concrete validation gates:

text
✔  Lab set up: client VM, hostile server
✔  Cluster 2 write primitive measured
✔  Control-flow hijack demonstrated
✘  libc base from the cluster 28 leak
── researcher intervention 1 ──
✔  libc base recovered
✔  ASLR defeated
✘  Working payload
── researcher intervention 2 ──
✔  Leak and write composed into one session
→  /tmp/pwned
RCE attempts on the client side
RCE attempts on the client side

Conclusion

On FreeRDP, the workflow produced 130 findings across two slices, triaged to 36 clusters, with 20 reproduced as real. Two findings provided the primitives chained into client-side remote code execution.

From git clone to the report sent to maintainers took four days on a roughly half-million-line C codebase audited and fuzzed for years. The AI model was only one component — surrounded by a queryable graph, deterministic analysis, bounded slices, dynamic ASan validation, an exploitation harness, and researcher checkpoints.

Advisories:

References

  1. The AI-Assisted Breach of Mexico's Government Infrastructure (Eyal Sela, Gambit Security, technical report, April 2026)
  2. Disrupting the first reported AI-orchestrated cyber espionage campaign (Anthropic, November 2025)
  3. The end of the curl bug-bounty (Daniel Stenberg, January 2026)
  4. Death by a thousand slops (Daniel Stenberg, July 2025)
  5. From Naptime to Big Sleep (Google Project Zero, November 2024)
  6. Google's AI security announcements (CVE-2025-6965)
  7. Introducing Aardvark: OpenAI's agentic security researcher (OpenAI, October 2025)
  8. Codex Security: now in research preview (OpenAI, March 2026)
  9. AI Cyber Challenge marks pivotal inflection point for cyber defense (DARPA, August 2025)
  10. FreeRDP sources (GitHub)

📦 Full-Text Markdown Snapshot archived by Phying News · Original source: blog.quarkslab.com