Papers
Topics
Authors
Recent
Search
2000 character limit reached

ChainFuzzer: Testing Multi-Tool Vulnerabilities

Updated 5 July 2026
  • ChainFuzzer is a greybox security testing framework for identifying workflow-level vulnerabilities in LLM agents.
  • It combines sink-centered chain extraction, trace-guided prompt solving, and guardrail-aware fuzzing to reveal chained vulnerabilities across multiple tools.
  • Evaluated on 20 LLM agent apps, it confirmed 365 reproducible vulnerabilities, highlighting significant risks from multi-tool workflow compositions.

ChainFuzzer is a greybox security testing framework for workflow-level multi-tool vulnerabilities in LLM agents. It targets unsafe behaviors that arise when one tool’s output becomes another tool’s input across multi-step workflows, including propagation through files, database records, caches, or retrieval indexes, so that exploitable source-to-sink dataflows emerge only through tool composition. The framework combines sink-centered chain extraction, Trace-guided Prompt Solving (TPS), and guardrail-aware fuzzing with sink-specific oracles, and was evaluated on 20 popular open-source LLM agent apps comprising 998 tools, where it extracted 2,388 candidate tool chains, synthesized 2,213 stable prompts, and confirmed 365 unique, reproducible vulnerabilities across 19/20 apps, including 302 that require multi-tool execution (Wu et al., 13 Mar 2026).

1. Problem domain and conceptual framing

ChainFuzzer is motivated by the observation that tool-augmented LLM agents routinely execute multi-step, multi-tool workflows in which one tool’s output is persisted or transformed and later reused by another tool. This design expands the attack surface because data produced by one tool can become the effective input to a later high-impact operation, even when no single tool invocation appears dangerous in isolation. The canonical pattern is a source-to-sink path such as

web_search→download→write_file→execute,\texttt{web\_search} \rightarrow \texttt{download} \rightarrow \texttt{write\_file} \rightarrow \texttt{execute},

where untrusted remote content is gradually promoted into executable input (Wu et al., 13 Mar 2026).

The framework defines the target class as multi-tool vulnerabilities in LLM agents: unsafe behaviors that depend on composition, state, and long-range dependency rather than on a single prompt directly causing a single tool call. Existing discovery efforts focused on single-tool or single-hop testing are characterized as inadequate for two stated reasons. First, they miss long-horizon composition, because a dangerous effect may require several intermediate steps before any sink is reached. Second, they provide limited debugging value, because developers need workflow-level causality: the ingress point, the intermediate carriers, the transforming tools, and the sink parameter that became tainted.

Three operational difficulties structure the design. The first is the combinatorial space of possible tool combinations, most of which are meaningless or infeasible. The second is LLM non-determinism: even when a plausible chain is known, the agent may skip steps, select different tools, misbind parameters, or fail at runtime. The third is the presence of intrinsic LLM guardrails, which can block direct malicious payloads and therefore hide genuine tool-workflow design flaws unless payloads are adapted while preserving the chain.

2. Threat model, sources, sinks, and dependency structure

ChainFuzzer assumes a deployment-oriented setting in which the attacker does not modify agent code, tool implementations, model weights, or developer secrets, and relies only on privileges already granted to the agent’s tools. Untrusted data may enter from two source classes: user-source injection, in which the payload enters via the user’s prompt or another user-controlled field, and env-source injection, in which the payload enters through external resources or shared carriers such as web pages, downloaded files, database rows, retrieval indexes, or caches (Wu et al., 13 Mar 2026).

A sink is a high-impact operation implemented by a tool, but ChainFuzzer is strict about sink labeling. A tool is treated as a sink tool only when a dangerous API call exists and a tool input can influence the sink argument through backward intra-tool dataflow. The sink-tool criterion is expressed as

SinkTool(t)=1  ⟺  ∃c∈SinkCallsites(t)  s.t.  Reachable(Input(t),Arg(c)).\text{SinkTool}(t) = 1 \iff \exists c \in \text{SinkCallsites}(t)\; \text{s.t.}\; \text{Reachable}(\text{Input}(t), \text{Arg}(c)).

Sink class Representative APIs
CMDi subprocess.run, os.system, os.popen, spawn*
CODEi eval, exec
SSRF requests.get/post/request, urllib.request.urlopen, httpx, aiohttp
SSTI jinja2.Environment.from_string, flask.render_template_string
SQLi sqlite3.Cursor.execute, SQLAlchemy execute variants, Django cursor execution

Cross-tool dependencies are divided into two types. Direct dependencies are output-to-input propagations, such as a tool returning a url later consumed as a url parameter. Indirect dependencies are propagations via shared carriers, such as one tool writing a file or database record that a later tool reads or executes. A candidate chain is an upstream-to-sink sequence of tools ending at a sink tool and retained only after semantic filtering if it forms a plausible workflow. A confirmed vulnerability requires a candidate chain, a stable prompt that reliably executes it, a payload inserted at a valid source, and a sink-specific oracle observation.

3. Sink-centered chain extraction

ChainFuzzer begins from a tool set

T={t1,t2,…,tn}\mathcal{T} = \{t_1, t_2, \dots, t_n\}

and reduces the search space by starting from high-impact sink tools rather than enumerating arbitrary tool sequences. It first scans source code against a sink API catalog and then performs strict intra-tool backward tracing from sink arguments through assignments, intermediate variables, and common code structures to determine whether a sink argument is reachable from tool entry inputs (Wu et al., 13 Mar 2026).

From each sink tool, the framework reconstructs upstream chains using two static edge rules. A direct dependency edge is added when an upstream return field can satisfy a downstream parameter under interface-level equivalence or containment. An indirect dependency edge is added when an upstream tool persists content and a downstream tool later reads or executes that persisted artifact. Because these rules over-approximate, ChainFuzzer applies an LLM semantic filter to eliminate chains that are type-compatible but workflow-incoherent.

The resulting structure is a set of sink-related candidate chains, optionally annotated with a key dependency site indicating which upstream artifact or field is most likely to influence the sink argument. On a manual validation of 200 sampled chains from the 2,388 extracted candidates, the framework reported edge precision

714740=96.49%\frac{714}{740}=96.49\%

and strict chain precision

183200=91.50%.\frac{183}{200}=91.50\%.

The strict metric counts a chain as correct only if all predicted edges are correct, so these results indicate that the extracted chains are usually precise enough to support prompt synthesis and downstream validation.

4. Trace-guided Prompt Solving

For a target chain

C=⟨t1,…,tk⟩,C=\langle t_1,\dots,t_k\rangle,

ChainFuzzer uses TPS to synthesize a prompt that causes the agent to execute that exact sequence reliably. An initial seed prompt is generated from the target chain, tool descriptions, and tool interfaces. The agent is then executed with the current prompt, producing a runtime trace

τi=⟨m,t,a,r,e⟩,\tau_i = \langle m, t, a, r, e \rangle,

where mm is the model’s thought or reasoning text, tt the invoked tool, aa the tool arguments, SinkTool(t)=1  ⟺  ∃c∈SinkCallsites(t)  s.t.  Reachable(Input(t),Arg(c)).\text{SinkTool}(t) = 1 \iff \exists c \in \text{SinkCallsites}(t)\; \text{s.t.}\; \text{Reachable}(\text{Input}(t), \text{Arg}(c)).0 the tool return value, and SinkTool(t)=1  ⟺  ∃c∈SinkCallsites(t)  s.t.  Reachable(Input(t),Arg(c)).\text{SinkTool}(t) = 1 \iff \exists c \in \text{SinkCallsites}(t)\; \text{s.t.}\; \text{Reachable}(\text{Input}(t), \text{Arg}(c)).1 the execution status (Wu et al., 13 Mar 2026).

When the observed trace diverges from the target chain, ChainFuzzer uses an LLM-based constraint generator to compare SinkTool(t)=1  ⟺  ∃c∈SinkCallsites(t)  s.t.  Reachable(Input(t),Arg(c)).\text{SinkTool}(t) = 1 \iff \exists c \in \text{SinkCallsites}(t)\; \text{s.t.}\; \text{Reachable}(\text{Input}(t), \text{Arg}(c)).2 with SinkTool(t)=1  ⟺  ∃c∈SinkCallsites(t)  s.t.  Reachable(Input(t),Arg(c)).\text{SinkTool}(t) = 1 \iff \exists c \in \text{SinkCallsites}(t)\; \text{s.t.}\; \text{Reachable}(\text{Input}(t), \text{Arg}(c)).3 and derive a compact semantic repair set SinkTool(t)=1  ⟺  ∃c∈SinkCallsites(t)  s.t.  Reachable(Input(t),Arg(c)).\text{SinkTool}(t) = 1 \iff \exists c \in \text{SinkCallsites}(t)\; \text{s.t.}\; \text{Reachable}(\text{Input}(t), \text{Arg}(c)).4. The five failure categories are missing preconditions, incorrect or incomplete argument bindings, format or parameter mismatches, permission or confirmation gates, and planner detours. The prompt solver then performs local repair rather than wholesale rewriting: SinkTool(t)=1  ⟺  ∃c∈SinkCallsites(t)  s.t.  Reachable(Input(t),Arg(c)).\text{SinkTool}(t) = 1 \iff \exists c \in \text{SinkCallsites}(t)\; \text{s.t.}\; \text{Reachable}(\text{Input}(t), \text{Arg}(c)).5 This constrains prompt search to edits that preserve what already works while encoding the missing conditions extracted from the trace.

A prompt is accepted as stable only when the full target chain executes successfully in five consecutive runs. In a 200-chain evaluation sample, TPS increased reachability over SinkTool(t)=1  ⟺  ∃c∈SinkCallsites(t)  s.t.  Reachable(Input(t),Arg(c)).\text{SinkTool}(t) = 1 \iff \exists c \in \text{SinkCallsites}(t)\; \text{s.t.}\; \text{Reachable}(\text{Input}(t), \text{Arg}(c)).6 repeated runs from SinkTool(t)=1  ⟺  ∃c∈SinkCallsites(t)  s.t.  Reachable(Input(t),Arg(c)).\text{SinkTool}(t) = 1 \iff \exists c \in \text{SinkCallsites}(t)\; \text{s.t.}\; \text{Reachable}(\text{Input}(t), \text{Arg}(c)).7 to SinkTool(t)=1  ⟺  ∃c∈SinkCallsites(t)  s.t.  Reachable(Input(t),Arg(c)).\text{SinkTool}(t) = 1 \iff \exists c \in \text{SinkCallsites}(t)\; \text{s.t.}\; \text{Reachable}(\text{Input}(t), \text{Arg}(c)).8, and improved the stable prompt rate under the 5/5 criterion from SinkTool(t)=1  ⟺  ∃c∈SinkCallsites(t)  s.t.  Reachable(Input(t),Arg(c)).\text{SinkTool}(t) = 1 \iff \exists c \in \text{SinkCallsites}(t)\; \text{s.t.}\; \text{Reachable}(\text{Input}(t), \text{Arg}(c)).9 to T={t1,t2,…,tn}\mathcal{T} = \{t_1, t_2, \dots, t_n\}0. These results identify prompt stabilization, rather than chain extraction alone, as a decisive factor in reproducing long-horizon agent workflows.

5. Guardrail-aware fuzzing and sink-specific validation

After a stable prompt is found, ChainFuzzer performs payload validation at the earliest plausible ingress on the chain. If the first tool consumes user-provided content, the framework tests user-source injection; if the chain relies on external content or shared artifacts, it tests env-source injection; and if both are plausible, both are exercised (Wu et al., 13 Mar 2026).

Payloads are instantiated according to sink type. CMDi receives command strings, CODEi executable code fragments, SSRF destination URLs, SQLi query fragments, and SSTI template expressions. Validation then relies on sink-specific oracles. For CMDi and CODEi, the sink API must be reached with payload-influenced arguments and the corresponding execution effect observed. For SSRF, the request API must be reached with a payload-influenced destination resolving to an SSRF probe target class such as internal, loopback, link-local, or a designated internal endpoint. For SQLi and SSTI, ChainFuzzer requires query- or template-evaluation effects rather than merely syntactic evidence.

If a direct malicious payload is blocked by the model’s intrinsic guardrails, the framework keeps the stable prompt fixed and mutates only the payload. The three mutation families are sharding, which splits a payload into benign-looking fragments that are reassembled downstream; encoding, which uses base64 or escaping; and format perturbation, which changes quoting, separators, or argument layout while preserving sink semantics. In a component evaluation over 100 verified vulnerabilities—20 per sink class, with five trials per payload strategy—the overall payload-level trigger rate increased from T={t1,t2,…,tn}\mathcal{T} = \{t_1, t_2, \dots, t_n\}1 T={t1,t2,…,tn}\mathcal{T} = \{t_1, t_2, \dots, t_n\}2 to T={t1,t2,…,tn}\mathcal{T} = \{t_1, t_2, \dots, t_n\}3 T={t1,t2,…,tn}\mathcal{T} = \{t_1, t_2, \dots, t_n\}4. Per-sink improvements were reported as T={t1,t2,…,tn}\mathcal{T} = \{t_1, t_2, \dots, t_n\}5 for CMDi, T={t1,t2,…,tn}\mathcal{T} = \{t_1, t_2, \dots, t_n\}6 for CODEi, T={t1,t2,…,tn}\mathcal{T} = \{t_1, t_2, \dots, t_n\}7 for SSRF, T={t1,t2,…,tn}\mathcal{T} = \{t_1, t_2, \dots, t_n\}8 for SSTI, and T={t1,t2,…,tn}\mathcal{T} = \{t_1, t_2, \dots, t_n\}9 for SQLi.

6. Empirical profile, limitations, and defensive implications

The evaluation covered 20 popular open-source multi-tool LLM agent applications selected by star ranking, with inclusion criteria of at least 2,000 GitHub stars and support for multi-tool workflows. Across these apps, ChainFuzzer analyzed 998 total tools and 199 sink tools, extracted 2,388 candidate tool chains, and synthesized 2,213 stable prompts. It confirmed 365 unique reproducible vulnerabilities across 19/20 apps, of which 302 required multi-tool execution and 63 were single-tool, so multi-tool vulnerabilities accounted for

714740=96.49%\frac{714}{740}=96.49\%0

of the findings and were 714740=96.49%\frac{714}{740}=96.49\%1 as common as single-tool ones 714740=96.49%\frac{714}{740}=96.49\%2 (Wu et al., 13 Mar 2026).

The study also reports source and sink distributions. By source, 225 vulnerabilities 714740=96.49%\frac{714}{740}=96.49\%3 were user-source and 140 714740=96.49%\frac{714}{740}=96.49\%4 env-source. By sink, CMDi accounted for 121 findings 714740=96.49%\frac{714}{740}=96.49\%5, CODEi 79 714740=96.49%\frac{714}{740}=96.49\%6, SSRF 97 714740=96.49%\frac{714}{740}=96.49\%7, SSTI 23 714740=96.49%\frac{714}{740}=96.49\%8, and SQLi 45 714740=96.49%\frac{714}{740}=96.49\%9. Runtime cost over the full dataset was 68.00 hours, 236,000 tool calls, and 120.80M tokens, with averages of 3.40 hours per app, 11,800 tool calls per app, and 6.04M tokens per app. Average time-to-first-vulnerability was 0.32 hours per app, and overall efficiency was reported as

183200=91.50%.\frac{183}{200}=91.50\%.0

Ablation results isolate the contributions of the three modules. Without ChainExtraction, the system found 63 vulnerabilities and only 3 sink types. Without TPS, it found 96 vulnerabilities and 4 sink types. Without Mutation, it found 132 vulnerabilities while still covering 5 sink types. This decomposition supports a division of labor in which ChainExtraction identifies where vulnerabilities could exist, TPS makes those workflows executable, and Mutation makes them confirmable under guardrails.

The main limitations are environment dependence and LLM dependence. Reproducibility can fail when network egress, sandbox permissions, or credentials differ from the evaluation setting, and multiple ChainFuzzer modules rely on LLM reasoning for semantic filtering, prompt repair, and payload mutation. A further limitation is the strict 5/5 stability criterion, which improves reproducibility but may exclude intermittently reachable vulnerabilities. The framework also explicitly excludes attacks requiring code modification, tool compromise, model-weight access, or privileges beyond those already granted to the agent.

The defensive implications are correspondingly sink- and workflow-oriented. The paper advocates sink-side input constraints, explicit mediated cross-tool state instead of ambient artifact reuse, and lightweight dataflow-aware checks before dangerous sink calls. This suggests that, in multi-tool agent systems, prompt-level safeguards are insufficient unless they are paired with typed artifact handling and source-to-sink enforcement at tool boundaries.

Definition Search Book Streamline Icon: https://streamlinehq.com
References (1)

Topic to Video (Beta)

No one has generated a video about this topic yet.

Whiteboard

No one has generated a whiteboard explanation for this topic yet.

Follow Topic

Get notified by email when new papers are published related to ChainFuzzer.