Tau: The Reference Harness to Attack and Harden

SDD-B11 · Course 2B — Securing & Attacking Harnesses and LLMs

45 minutes · The map from B1's seven surfaces to five explicit extension points in ~3,000 lines of Python

Tau is the target. Every defense in B2–B8 is a missing feature in tau today — and every one attaches at a clean extension point. This deep-dive is the map.

Deep-Dives

What tau is — and why it is the target

Hugging Face's educational reimplementation of Pi (Course 1 DD-01). Built by Alejandro AO. ~3,000 LOC across three packages. A working coding agent with real tools, real credentials, real sessions.

The three-layer split

tau_ai — provider/model streaming (provider-neutral)
tau_agent — reusable brain: harness, loop, tools, events
tau_coding — coding app: CLI/TUI, read/write/edit/bash, sessions

The load-bearing boundary

AgentHarness = reusable brain
CodingSession = coding environment
TUI = one possible frontend
Core knows nothing about rendering

Three properties that make tau ideal

PropertyWhat it means
It is realA bash tool that actually runs asyncio.create_subprocess_shell. A credential store that actually holds plaintext API keys on disk. When you attack tau, you attack a real system.
It is small~3,000 LOC across three packages. A student reads the entire codebase in an afternoon and understands every line that matters for security.
It is undefendedNone of the controls B2–B8 build exist today. The "before" picture — raw, injectable, exfiltratable. Every control you add is a net-new feature.
DD-01 was "the simplest harness that works." SDD-B11 is "the simplest harness we can break and fix."

B11.1 — The before picture: seven surfaces, zero defenses

tau's attack surface mapped to B-modules

Seven surfaces, all undefended today

SurfaceWhereModuleTau today
1. Agent looploop.py:190B1/B2no interception · executes on request
2. Tool outputloop.py:260B2/B4unfiltered into transcript
3. Sessionssession.py:1378B3no memory-write gate · JSONL poison persists
4. Providertau_aiB0no provider-authz check
5. Credentialscredentials.pyB5plaintext 0600 · bash can cat/printenv
6. Sandboxtools.py:470B7zero isolation · no egress/allowlist
7. Observabilityevents.pyB8events emitted · no listener analyzes
Enforcement belongs in the tool, not the loop. The loop delegates to tool.executetool.executor. You do not patch run_agent_loop. The architectural lesson: wrap the executor.

B11.2 — The five extension points

Where each control attaches — wrapping, replacing, subscribing

Tau has no plugin system — and that is a feature

No register_tool. No hook framework. No middleware. Verified by grepping the entire source. Every control attaches by wrapping or replacing objects at explicit, named sites.
Extension pointWhereModuleMechanism
1 Executor wrappingtools.py:61B2/B4replace(tool, executor=gated)
2 Bash factorytools.py:574B7replace create_bash_tool
3 Credential storeprovider_runtime.py:46B5vault implements CredentialReader
4 Event subscriptionharness.py:124B8harness.subscribe(listener)
5 Tool-list constructionsession.py:286B0/B1inject CodingSessionConfig.tools
Four of five are wrapping/additive — no monkey-patching. Every wedge point is auditable and teachable.

Extension Point 1 — the executor wrapper

@dataclass(frozen=True, slots=True)
class AgentTool:
    name: str
    description: str
    input_schema: Mapping[str, JSONValue]
    executor: ToolExecutor   # ← the wedge
    prompt_snippet: str | None = None

def wrap_with_gate(inner: AgentTool, gate) -> AgentTool:
    async def gated(arguments, signal=None):
        gate.inspect(inner.name, arguments)   # pre-execution
        result = await inner.executor(arguments, signal=signal)
        return gate.sanitize(inner.name, result)  # post-execution
    return replace(inner, executor=gated)
No monkey-patching. No subclassing. No framework registration. A wrapping function and a dataclass replace. The taint gate (B2) and the injection detector (B2 Layer 4) attach here.

B11.3 — The two-bash-tool finding

Why a tool-list wedge is bypassable — and the factory-level fix

The two-bash-tool finding

create_bash_tool factory (tools.py:574)
        │
   ┌────┴────┐
   ▼         ▼
 PATH 1    PATH 2 — run_terminal_command
 harness   (session.py:1183)
 list      constructs its OWN create_bash_tool
           calls it directly at session.py:1187
           NEVER enters CodingSessionConfig.tools

 A B7 sandbox that wraps only EP1 (tool list)
 is BYPASSED by PATH 2 — it never sees it.

 FIX: replace create_bash_tool ITSELF
      → both paths receive the sandbox policy
The factory is the chokepoint. Any control wedging at the tool-list layer is bypassable by any code path that constructs its own tool outside the list. Wedge at the factory, not the instance.

The hardened session: all five assembled

EP5 + EP1 — inject hardened tools at CodingSession.load. Every executor wrapped: scope gate (B0/B1), taint gate (B2), output tagged <untrusted>.
EP2 — hardened create_bash_tool replaces the factory. BOTH paths covered. Default-deny egress, allowlist, resource caps (B7).
EP3 — vault replaces FileCredentialStore in both sites. Credentials never plaintext on disk; agent cannot reach the store (B5).
EP4 — intent tracker subscribed via harness.subscribe. Read-only observability (B8). Enforcement is EP1.
The composition is the point. No single extension point suffices. The scorecard measures the delta between unmodified tau and this hardened session — the artifact Capstone B1 ships.

Anti-patterns this map prevents

Anti-patternCure
Patching run_agent_loop to add a gateWrap the executor (EP1). The loop delegates to tool.executor.
Wrapping only the harness bash toolWedge at the factory (EP2). run_terminal_command builds its own.
Overloading shell_command_prefix as allowlistIt is a blind prepend — cannot see/reject. Wrap the executor.
Looking for register_toolNone exists. Construct a custom CodingSessionConfig.
Using the event listener for enforcementEvents fire after the decision — read-only. Enforcement is EP1.

Lab & what's next

Lab (07): clone tau, run the injection battery against the unmodified codebase using planted injection content, identify each surface's extension point, and map every finding to a B-module control. Python, type hints, no GPU.

This deep-dive is the prerequisite for Capstone B1 (harden tau — install the plugins from this map) and Capstone B2 (red-team a tau deployment — attack a partially-hardened instance). The delta is the scorecard.