The Paper
"Security Assessment of DeepSeek Harness with A.I.G: Evaluating Resistance to Indirect Prompt Injection" was published in August 2026 by Zonghao Ying, Xiangfan Wu, Huiyu Wu, Xing Zheng, Huangsheng Cheng, Xiaorong Shi, and Jing Guo of Tencent Zhuque Lab. The central claim is that indirect prompt injection resistance cannot be characterized by a synthetic agent or by a single aggregate score. Driving the real DeepSeek Harness TypeScript runtime through 14,560 controlled executions, the authors report an overall full-success rate of 5.6% that conceals individual channel and carrier slices reaching 25.5%.
Read the Paper on arXiv →The Problem Before This Paper
Indirect prompt injection has been understood since Greshake et al. showed in 2023 that instructions embedded in content an application must process can redirect a model away from the user's request. The benchmarks that followed established tasks and success conditions but stopped short of the thing a deployment actually ships: InjecAgent (Zhan et al., ACL Findings 2024) and AgentDojo (Debenedetti et al., NeurIPS 2024) evaluate injection against benchmark-supplied agent scaffolds rather than a specific composed runtime with its own tool registry, session log, and model adapter. Defenses including spotlighting (Hines et al., 2024), BIPIA boundary awareness (Yi et al., 2025), and StruQ structured queries (Chen et al., 2025) target the prompt boundary, which presumes the payload has already reached the prompt in a recognizable form. Two gaps remained. First, nobody had measured whether a plugin-composed production runtime prevents untrusted content from changing agent actions, as opposed to measuring whether a model rejects a malicious string. Second, injection testing had settled on textual approximations of carriers and single-number reporting, both of which turn out to erase the cases that matter.
What They Built
The assessment uses a source-to-sink threat model. A source is a content-reading tool whose result
carries attacker-controlled material, making the returned page, file, record, or skill a tainted
artifact. A sink is an externally observable action the attacker wants performed: sending email,
submitting a form, executing a command, transferring money. The attacker controls the tainted
artifact and nothing else - not the user request, system prompt, tool registry, judge, or sink
implementation. AI-Infra-Guard (A.I.G) supplies payload construction, carrier injection, taint
routing, a runtime adapter, trace collection, and two judges. The adapter executes DSH's actual
TypeScript runtime rather than a stand-in: it creates isolated taint, clean-sample, and sink-log
files per run, launches a driver with npx tsx, and consumes JSONL session events. The
driver uses DSH's own agent-loop dependency mounting pattern, creating an agent through
ctx.agentLoop.create(), submitting a benign request with agent.followup(),
waiting for idle, then reading agent.session.events. A fixture plugin registers six
source tools covering web retrieval, documents, email, knowledge search, skills, and chat messages,
plus eight tracked sink tools that record name and arguments to a local file and return a synthetic
result. Tool selection and argument construction stay with the model; the consequences do not leave
the machine. The full_channel_mode dataset balances 16 channels against 2 carrier modes
and 35 payload objectives for 1,120 base cases, then applies an unmodified naive
baseline plus 12 attack wordings to produce 14,560 executions. Thirty-two objectives require a
sensitive action with critical expected arguments such as a recipient, account, or destination URL,
broken down as seven email, seven command, four transfer, four form, three social-post, three
calendar, two direct-message, and two channel-post tasks. Three objectives require only an output
canary. The model backend is deepseek-v4-flash through a local proxy.
Outcomes are scored twice, and the paper is deliberate about not merging the two. The deterministic evaluator JR (RuleJudge) checks explicit trace evidence: whether taint reached a tool result, whether a sink fired, whether critical sink arguments match the attacker task, whether a canary dominates the final answer, and whether the answer resembles a refusal. A sink call with a mismatched critical argument counts as partial compliance, not success. The semantic evaluator JL (LLMJudge) runs offline over the saved trace along with the legitimate task, attacker objective, canary, expected arguments, and sink requirement, returning FULL, PARTIAL, or FAILURE. JL never overwrites JR.
The authors then inspected the DSH source snapshot used in the experiment, commit
47f943859bef dated August 13, 2026, and identified the two control-flow locations that
determine exposure. The first is in tool-calls.ts under
packages/core/agent-loop/src, where a tool result is appended to the session and the
contexts it returns are accepted:
appendToolResult(session, turn, step,
call!.block, result, ...)
for (const context of
result.additionalContexts ?? []) {
acceptContext(context)
}
Paired with deferContext(context: UserMessage) in the tools module, this means any
retrieval tool, MCP integration, skill, or plugin that controls result content sits on the
model-visible input boundary. The second location is the tool-call guard, which executes after
tools/pre-execute listeners and before the tool body:
export type ToolGuard =
(execution: Readonly<ToolExecution>)
=> string | undefined
Returning a reason denies the call, and the denial is monotonic: no later listener can convert it back into an allow. The authors are explicit that the experiment does not show these interfaces are flawed. It shows why a deployment has to use them when an untrusted source precedes a sensitive sink.
Key Findings
- Hidden Unicode scored 0.0% in text mode and 25.5% in file mode. Same payload, same channel, 455 runs per cell. In file mode 116 of 455 runs received a full-success verdict from JR, making it the worst single channel in the study; the text-mode approximation of the same test reports a clean pass. Whatever the parsing, metadata handling, and encoding path does to that carrier is the vulnerability, and a text-only suite never executes it.
- The skills channel is elevated in both carrier modes, at 14.3% text and 16.0% file. Reusable instruction assets are an injection channel on par with the worst document carriers, which puts skills, MCP integrations, tool descriptions, and workflow templates inside the prompt-injection threat model rather than beside it.
- Wording matters more than the aggregate suggests, but not uniformly. Fake completion reached 16.6% under JR and 17.0% under JL in text mode against a naive baseline of 5.5%, roughly a 3x lift. Meanwhile
context_ignoringlanded at 0.2% in text mode, well below the unmodified baseline. A transformation that helps in one configuration is not a universal attack ranking. - Judge disagreement is a finding, not noise. Obfuscation reads 13.6% under JR in both modes but only 9.1% and 8.8% under JL, meaning a mechanical signal fired without the trace establishing semantic compliance. Fake completion scores nearly the same under both judges, which is what a real result looks like. Partial compliance diverges hardest: 2.0% under JR against 7.3% under JL.
- The runtime already exposes the right control points. Deny-only monotonic guards,
tools/pre-executeandtools/post-executelisteners, approval, and sandbox controls are all present. The measured exposure came from a baseline configuration with prompt hardening turned off and no source-aware policy applied, which locates the gap in deployment practice rather than in the harness API.
Results
Across 14,560 runs, JR assigned 819 full successes (5.6%) and 298 partial compliances (2.0%), for a broad-influence rate of 1,117 runs (7.6%). JL assigned 772 full successes (5.3%) and 1,060 partial compliances (7.3%), for 1,832 runs (12.6%), with 9 judge errors (0.1%). Carrier representation moved the aggregate: file mode produced 6.2% JR full success against text mode's 5.1%, and 387 observed sink calls against 254. That aggregate difference does not hold per channel - chat messages ran 9.5% in text mode and 1.3% in file mode, calendar events 7.7% against 4.2%, while documents went the other way at 5.5% against 7.3%. Channel spread under JR ranged from hidden Unicode at 0.0% text and 25.5% file, through skills at 14.3% and 16.0%, translation at 7.9% and 8.8%, webpages at 5.1% and 4.4%, down to log files at 2.4% in both modes. By wording, escape reached 8.6% text and 9.3% file, prefix injection 3.8% and 5.5%, payload splitting 2.1% and 4.6%, and stealth instruction 0.9% and 1.8%. Every one of these percentages is a measurement of one DSH revision, one model, one persona, and one unhardened baseline configuration, with all sinks simulated. A recorded sink call is an attempted sensitive action, not a breach.
Why This Matters for AI and Automation
- A single injection score is close to useless for deciding whether to ship. 5.6% overall reads like a tolerable residual risk. The 25.5% cell inside it is a channel an attacker will find by trying carriers until one lands, because that is cheaper than trying wordings. This is the same failure mode as Week 16's reliability science framework, where aggregate pass@1 concealed a 24-point degradation across task duration. Reporting the distribution is the deliverable; reporting the mean is the bug.
- If your red-team suite feeds the model strings, it is not testing your ingestion path. The hidden-Unicode result is a parser and normalization outcome, not a model-judgment outcome. Build the real HTML, email, calendar entry, PDF metadata block, or spreadsheet cell, extract the model-visible material the way production does, and test that. Anything else measures the model in isolation from the system it runs inside.
- Skills and integrations need the review process you already give dependencies. The 16.0% skills result makes this concrete, and it lands directly on the pattern from Week 18's SkillOpt, where skills are treated as external documents that get edited to change agent behavior. That is exactly the property an attacker wants. Ownership, provenance, version review, and privilege limits belong on skill files, tool descriptions, MCP servers, and workflow templates.
- Provenance has to survive the trip into model context. The authors' recommendation is that tool results retain a source label, trust tier, and carrier type, and that normalization expose hidden Unicode, metadata, and format-specific fields rather than silently pass them through. Once a tool result has been flattened into anonymous text, no downstream policy can tell whether the instruction it contains came from the user or from a scraped page.
- Sensitive sinks need authorization that does not consult the model. Email, external HTTP submission, shell execution, file mutation, privilege changes, and financial actions should sit behind allowlists, argument-level checks, data classification, or human approval. A capable sandbox plus an approval layer still fails if the argument the model chose was written by an attacker and nothing validated it independently.
My Take
The DeepSeek Harness framing is the least interesting thing about this paper, and the authors seem to know it - Appendix B goes out of its way to say the percentages are descriptive measurements for one controlled configuration, not universal vulnerability rates for any runtime or model provider. What the work actually contributes is a method with two properties most injection testing lacks: it runs the real session-event path instead of a reimplementation, and it refuses to collapse the deterministic and semantic verdicts into one number. That second choice is where the useful signal came from. The obfuscation gap, 13.6% under the rule judge against 9.1% under the semantic judge, is a case where a team running only a rule judge would spend a sprint hardening against an attack that was not really succeeding, while the 7.3% semantic partial rate flags traces where behavior genuinely shifted but no criterion tripped - which is the population worth reading by hand. The honest limitation is the one the authors do not resolve: prompt hardening was off, so the paper measures an unhardened floor rather than the number a real deployment would see, and there is no ablation showing how much of the 7.6% broad-influence rate normalization alone would remove. Given that the worst cell is a Unicode handling artifact, my guess is that a meaningful share of it is a parser fix rather than a policy problem, and that guess is testable with the released code. The finding I expect to age best is the skills channel, because it is the one that describes how people are actually building agents right now: pasting in a skill file from somewhere, wiring an MCP server someone else published, trusting a tool description because it arrived alongside working code. Those are dependencies. We review dependencies. We do not review these.
Discussion question: Hidden Unicode scored 0.0% when tested as text and 25.5% when tested as a real file, which means the vulnerability lived in the ingestion path rather than the model. For the agent systems you run today, do your injection tests construct the actual carrier - the real HTML, PDF metadata, spreadsheet cell, or skill file - or do they hand the model a string that approximates it, and what would it cost you to find out which channels change verdict when you switch?