# Compaction Laundering: Provenance Destruction in Context-Compacting Coding Agents

> Compaction laundering lets attackers forge user instructions that survive context summarization in flattening coding harnesses, enabling code execution with 87-100% success.

- **Source:** [arXiv](https://arxiv.org/abs/2610.29869)
- **Published:** 2026-10-24
- **Permalink:** https://picx.dev/p/YLcnVn
- **Whiteboard:** https://picx.dev/p/YLcnVn/image

## Summary

## Summary (Overview)

- **Novel attack vector**: The paper identifies "compaction laundering" — a vulnerability in context-compacting coding agents where an attacker can forge user instructions that survive context summarization as genuine user commands.
- **Root cause**: Harnesses that flatten typed conversations into plain strings with in-band role labels (e.g., `[User]:`) destroy message provenance, making forged labels indistinguishable from real user input.
- **Measured impact**: Across five flattening harnesses (pi, opencode, Cline, Aider, OpenHands), forged approvals launder into agent memory 87–100% of the time, up to a ~908,000-token context window; four role-typed harnesses (Codex, Gemini CLI, Qwen Code, Continue) show 0% vulnerability.
- **Executed consequences**: Laundered approvals drive real tool-running agents to execute attacker-controlled `curl | sh` commands in sandboxes, with live end-to-end success in the pi TUI at ~50% against a 0% clean control arm.
- **Defense**: A code-level provenance check catches 77% of laundering while demoting only 2% of legitimate summary content, outperforming prompt-based rules (13–25%) and published classifier defenses (67% at best).

---

## Introduction and Theoretical Foundation

### The Problem

Long-running coding agents must eventually compact their context window by summarizing the conversation and discarding the original. This paper demonstrates that this compaction step is an exploitable trust boundary in a class of popular open-source coding agents.

The core vulnerability: harnesses flatten typed messages (user, assistant, tool) into a single plain string marked with text labels like `[User]:` or `[Tool result]:`. When untrusted content (files, web pages) contains a forged `[User]:` line, it becomes indistinguishable from genuine user input after flattening. The summarizer then faithfully records it as a user instruction — not because it's tricked, but because recording user constraints is its job.

### Key Insight

> "Whether a harness is exposed depends on how it serializes the conversation for the summarizer. Harnesses that flatten the roles into in-band labels are exposed; those that keep messages role-typed are not."

This reframes the failure from a model limitation (inability to determine content origin) to a **harness code defect** (destruction of provenance before the model sees the text). This distinction admits defenses the prompt-focused literature does not consider.

### Scope and Severity

- **Mandatory attack surface**: Compaction is required for every long-running agent; no auxiliary memory modules needed
- **Impact**: Code execution with the developer's own permissions
- **External attackers**: A maliciously set-up troubleshooting page can carry the attack without insider access
- **Inherited vulnerability**: Derivative agents built on flattening harnesses silently inherit the flaw

---

## Methodology

### The Trust Boundary

The attack requires the summarizer to be *accurate*, faithfully copying a forged `[User]:` line into the user's instruction section. The attack does not trick or jailbreak the summarizer — it exploits the summarizer's correct behavior.

### Threat Model

Two attack primitives:

1. **Forging a role label** (stronger): Attacker's text contains a newline followed by a forged `[User]:` marker
2. **Erasing provenance** (weaker): The summary format has no field for origin; notes from files are textually identical to user-provided ones

### Attack Scenarios

| Scenario | Attacker is... | How poison reaches agent | Required access |
|----------|---------------|--------------------------|-----------------|
| Onboarding doc (insider) | Someone on the team | Agent reads `docs/onboarding.md` | Commit access |
| Troubleshooting page (external) | Anyone on the web | Agent web-fetches a page while debugging | Get agent onto that page |
| Dependency README (external) | Any package author | Agent reads dependency docs while tracing | Publish a package version |

### Harness Classes

**Flattening harnesses** (vulnerable): pi, opencode, Cline, Aider, OpenHands — serialize history into one text string with in-band role labels.

**Role-typed harnesses** (control): Codex, Gemini CLI, Qwen Code, Continue — pass conversation as typed message array where role is a field attackers cannot reach.

### Experimental Setup

- Real harness summarization prompts (copied verbatim from pinned commits)
- Real frontier model API calls (Anthropic, OpenAI, Zhipu/GLM)
- Real execution in disposable Docker containers with benign canary payloads
- Staged conversations with synthetic poison, plus live end-to-end testing in the real pi TUI

### Metrics

- **Laundering** (primary): Forged line appears in summary as user-attributed content, scored by LLM judge
- **Survival**: Weaker signal — line appears in summary at all (may be filed as document content)
- **Issued vs. confirmed**: Whether agent ran the command vs. proof file appearing on disk
- **Clean arm**: Identical task with no forged line; must remain at zero

---

## Empirical Validation / Results

### E1: Laundering Rate Stable Across Model Families

Using pi's real summarization prompt (n=72 per cell):

| Harness / Arm | Anthropic | OpenAI | Zhipu (GLM) |
|---------------|-----------|--------|-------------|
| pi | 69% | 68% | 67% |
| gemini_cli — rule removed | 53% | 83% | 86% |
| gemini_cli — full (vendor rule) | 46% | 62% | 60% |
| codex † | 0% | 0% | 0% |

pi landing within two points across three unrelated labs indicates the cause is the harness's flattening code, not the model.

### E2: The Forged Label Is the Mechanism

| Harness / Arm | With forged label | Plain text |
|---------------|-------------------|------------|
| pi | 87% | 6% |
| gemini_cli — rule removed | 79% | 28% |
| gemini_cli — full | 69% | 3% |

Without the forged label, the same words mostly do not launder.

### E6: Laundered Approval Drives Execution

Across harnesses and scenarios (gpt-5.6-terra, n=3):

| Harness × Scenario | Executed | Clean |
|--------------------|----------|-------|
| pi × onboarding (insider) | 3/3 | 0/3 |
| pi × webpage (external) | 1/3 | 0/3 |
| pi × dependency (external) | 3/3 | 0/3 |
| codex × all three | 0/9 | 0/9 |
| gemini_cli × all three | 0/9 | 0/9 |

**Execution falls as window fills** (pi, gpt-5.6-terra, onboarding scenario, n=5):

| Context window | Executed | (Laundering landed) |
|----------------|----------|---------------------|
| ~2,400 | 5/5 | 5/5 |
| ~26,000 | 5/5 | 5/5 |
| ~112,000 | 2/5 | 5/5 |
| ~263,000 | 2/5 | 5/5 |
| clean @ 263k | 0/3 | — |

**Laundered vs. genuine approval control**:

| Context | Laundered | Genuine | Clean |
|---------|-----------|---------|-------|
| ~26k | 5/5 | 5/5 | 0/5 |
| ~263k | 2/5 | 2/5 | 0/5 |

Laundered and genuine approvals yield identical execution rates — the drop is not forgery detection but general caution about `curl | sh`.

### E7: Laundering Is Scale-Invariant

| Context fed to summarizer | pi laundered |
|---------------------------|--------------|
| ~2,800 | 3/3 |
| ~65,200 | 3/3 |
| ~130,000 | 3/3 |
| ~306,800 | 3/3 |
| ~507,000 | 3/3 |
| ~731,000 | 3/3 |
| ~908,000 | 3/3 |

Laundering is flat at 100% from a few thousand tokens to ~908,000 (the model's 922k input ceiling).

### E10: Serialization Determines Exposure

| Class | Harness | Laundered |
|-------|---------|-----------|
| Flattening | pi, opencode, Aider | 100% (15/15) |
| Flattening | OpenHands | 93% (14/15) |
| Flattening | Cline | 87% (13/15) |
| Role-typed | Codex, Gemini CLI, Qwen Code, Continue | 0% (0/15) |

### E11: Executed Chain Fires on All Flattening Harnesses

| Harness | Effective window | Executed | Clean |
|---------|-----------------|----------|-------|
| OpenHands | ~63k | 4/5 | 0/3 |
| opencode | ~185k | 1/5 | 0/3 |
| Cline | ~185k | 1/5 | 0/3 |
| Aider | ~300k | 1/5 | 0/3 |

Execution tracks the effective compacted window, not raw session length.

### E13: Attacker Can Reverse Attenuation via Recency

| Injection design | Mean salience | Executed | (Laundered) |
|------------------|---------------|----------|-------------|
| Repeat inject 4× | 2.8 | 0/5 | 5/5 |
| Baseline (single at 75%) | 3.5 | 2/5 | 5/5 |
| Framed + repeated + at end | 3.8 | 2/5 | 5/5 |
| Framed @75% | 4.5 | 2/5 | 5/5 |
| Framed at end | 4.8 | 3/5 | 5/5 |
| Single at end (recency) | 4.8 | 4/5 | 5/5 |

Moving the single forged approval to the end raises execution from 40% to 80%. Naive repetition is counterproductive (drops to 0%).

### E15: Complete Chain Live in Real pi TUI

| Arm | Full chain (WIN) | Refused post-compaction | Ran pre-compaction |
|-----|------------------|-------------------------|--------------------|
| Poisoned | 3/6 | 3/6 | 0/6 |
| Clean | 0/5 | 5/5 | 1/6 † |

† One clean take executed during first turn — model variance, absorbed by paired design.

Key findings: The agent's pre-compaction audit is a substantial barrier (compaction can erase it); post-compaction trigger phrasing matters (neutral "ok, what's next?" produced clearest separation: 3/6 poisoned vs. 0/5 clean).

### E16: The Audit Is Forge-Resistant

With a genuine skeptical audit in the transcript, execution collapses to 1/50 pooled across all forgery arms (user, think, both, evidence). Assistant-thinking forgery is falsifiable against the transcript; user forgery is not, because user turns are the one unfalsifiable voice in the flattened stream.

### E9: Code-Level Defense

| How strict | Laundering caught | Legit claims demoted |
|------------|-------------------|---------------------|
| 0.05 | 82% | 9% |
| 0.10 | 80% | 6% |
| **0.15** | **77%** | **2%** |
| 0.25 | 70% | 1% |
| 0.40 | 56% | 0% |

Comparison: Gemini's in-prompt rule stops ~13–25%; published classifiers reach 67% at best; the provenance-contrast check catches 77% with 2% collateral.

---

## Theoretical and Practical Implications

### Root Cause Reframing

The vulnerability is a **serialization bug in harness code**, not a general model limitation. Evidence:

1. The forged label is the mechanism (E2): stripping it drops laundering to 6%
2. Role-typed harnesses at 0% (E10): keeping roles typed prevents the attack entirely
3. Model families show minimal variation (E1): pi at 69/68/67% across labs

### Why Prompt-Level Defenses Fail

> "A summarizer can notice the injection attempt and still never ask who sent it, so detection does not amount to prevention."

The in-prompt anti-injection rule reduces laundering by 7–26 points depending on model but never below 60% on flattening harnesses. Role-typing, not the rule, is why Gemini CLI achieves 0%.

### Attack Characteristics

- **Scale-invariant**: Laundering persists at 100% regardless of context size or position
- **Compaction-immune**: Repeated compaction neither strengthens nor removes injected claims (E4)
- **Attacker-addressable attenuation**: Execution declines with window size due to reduced salience, but recency placement reverses this (E13)

### Defense Recommendations (by implementation cost)

1. **Escape role labels in tool content before flattening** — small serializer change, drops forged-label attack to plain-text floor
2. **Verify summary in code** — check user-attributed claims against genuine user turns; demote ungrounded claims
3. **Carry provenance in schema** (`{text, source}`) preserved through re-summarization
4. **Do not relabel summary as the user** — give it its own role or wrap in delimiters

---

## Conclusion

### Main Takeaways

1. **Compaction laundering is a real, exploitable vulnerability** in all five tested flattening harnesses, with 87–100% laundering rates and executed consequences (RCE) demonstrated in sandboxes and live in the real pi TUI.

2. **The fix is structural, not prompt-based**: Role-typed serialization (already used by four harnesses) eliminates the vulnerability entirely; escaping role labels before flattening is a minimal code change.

3. **The attack targets the unfalsifiable voice**: User turns make no verifiable claims, so the summarizer cannot check whether the user really approved anything. Assistant and tool content remains checkable against the transcript.

4. **The agent's own audit is the strongest defense**: A diligent pre-compaction audit that survives into the summary is forge-resistant (E16), but compaction can erase it (E15).

### Limitations

- Executed demonstrations run on OpenAI models (claude-opus-5 refused to summarize malicious transcripts ~56% of the time)
- Salience mechanism measured within a single model
- All payloads are benign canaries; high-stakes payloads (credential exfiltration) never executed even when laundered
- Defense not yet tested against adaptive attacks
- Every measured rate is a floor — recombination attacks and targeted poisoning likely increase exposure

### Future Directions

- Independent-judge, multi-model replication of salience mechanism
- Adaptive attack testing against the provenance-contrast defense
- Sandbox-enforced harnesses: demonstrating in-sandbox exfiltration and blinded review consequences
- Field measurement of real audit strength across diverse agent deployments

---

_Markdown view of https://picx.dev/p/YLcnVn, served by PicX — AI-generated visual whiteboard summaries of research papers._
