Skip to content

Spike: classify a tainted session's outgoing calls for likely data extraction, with heuristics first and JEV for the ambiguous band #3434

Open

Description

@schlessera

The question

Can a host-side classifier tell a likely data-extraction attempt from an ordinary read, well enough to choose between auto-allow, ask and block for a tainted session's outgoing calls? Which signals carry the decision, and does JEV improve on deterministic heuristics enough to justify its cost, latency and data flow?

The classifier runs only once a session is tainted (G6, "Untrusted input (G6)", docs/decisions/governed-writable-workers.md:3760). It judges each outgoing call at admission:

  • WebFetch URL and prompt;
  • the full Bash command (curl -d …, gh … --body …);
  • MCP and brain CLI arguments;
  • provider-relay request bodies.

It does not see wire traffic. For HTTPS the turn proxy sees only CONNECT host:port and byte counts (packages/ui-sdk/src/server/egress-proxy.ts). Tool-call admission already sees full inputs: the Claude PreToolUse chain (packages/ui-backend-claude/src/permission-hooks.ts:546-578), the outward plan (prepareOutwardPlan, packages/ui-sdk/src/server/outward-policy.ts:45), and the provider relay.

What is blocked on the answer

#3430 was ruled on 2026-11-03: a tainted interactive session asks (a permission card per new host, with a session-scoped grant) rather than refusing. This spike measures whether a classifier can keep that prompt rare. If every new host asks, prompts become frequent enough to be rubber-stamped. A reliable classifier would let clean reads through and reserve the card for suspicious calls. The spike starts once #3430 is delivered, so it measures against the real prompt path.

How it gets answered

  1. Signals, deterministic first. Implement and score each one separately:

    • fingerprint overlap: shingle hashes of the outgoing request against brain files read in the session, the strongest signal;
    • the destination host appears in the content that tainted the session;
    • high-entropy or encoded blobs (base64, hex) in the path, query or subdomain;
    • query length and body size to a host the session has not used before;
    • write-shaped destinations: mail, issues, gists, paste sites, form endpoints;
    • fan-out: many calls or many distinct subdomains to one new host;
    • the request method and the tool's own read/outward classification.
  2. JEV as the middle-band judge. Run it only where the heuristic score is ambiguous. Its input is limited to the outgoing request, the name of the taint source and the overlap score. It never sees the conversation or the untrusted content, so the same injection cannot steer it.

  3. Labelled set. Use keyless Odysseus fixtures:

    • benign reads after a taint: lookups, documentation fetches, public APIs, gh reads, image prompts;
    • extraction attempts: brain text in a query string, base64 in a subdomain, a POST of a note to a paste site, chunked trickles, paraphrased leaks, an injected "send this to …" instruction.

    Include adversarial cases written to evade each heuristic.

  4. Measure precision and recall per action band (allow, ask, block) for heuristics alone and for heuristics plus JEV. Also measure latency and per-call cost, and the ask rate on a realistic benign session.

Constraints the design must hold:

  • Advisory only. It can escalate a call from allow to ask or block. It never relaxes deny, allowlist mode, budgets or outward-action rules.
  • Its own data flow. The JEV call sends request content to a provider. Route it under "Data-to-provider routing (G2)" (docs/decisions/governed-writable-workers.md:2395), meter it and budget it. When JEV is unavailable, the band falls back to ask.
  • Append-only history. No verdict enters the provider-facing conversation, except as the text of a refusal in that call's own tool result.
  • Keyless tests. Tests use a deterministic JEV stub, and live measurement stays out of CI.
  • Voice and autonomous turns stay on refusal, whatever the verdict.

Time box

Three working days for signals, the labelled set and measurement. Stop early if fingerprint overlap alone reaches high recall at an acceptable ask rate: that is a valid outcome, and JEV stays out.

Deliverable

A comment on this issue, or a docs/plans/ entry if it is large, containing:

  • the signal definitions and the request schema the classifier sees;
  • the labelled set, checked in as a keyless fixture;
  • the measured table per configuration;
  • a recommendation: heuristics only, heuristics plus JEV, or no classifier.

Then file implementation tasks under #3428 from it. Name the known evasions the classifier cannot catch, so the approval card stays the backstop.

Out of scope

Acceptance criteria

  • The signal definitions and the request schema the classifier sees are written down.
  • The labelled set (benign and extraction cases, including adversarial evasions per heuristic) is checked in as a keyless Odysseus fixture.
  • A table reports precision and recall per action band, latency, per-call cost and the benign-session ask rate, for heuristics alone and, unless the early-stop condition is met, for heuristics plus JEV.
  • The recommendation names the configuration and the known evasions the classifier cannot catch.
  • Live JEV measurement (unless the early-stop condition is met) stays within the $10 cap, runs outside CI, and the deliverable records spend, model version and sanitized results.
  • Implementation tasks are filed under Epic: session taint marks real untrusted input, and its restrictions are visible and decidable #3428.

Verification

Keyless tests over the fixture with a deterministic JEV stub run in CI. Any live JEV measurement is run outside CI under the recorded authorization above (cap $10), with spend, model version and sanitized results in the deliverable; no credential or account identifier in public evidence.

Contract impact

None for the spike. Implementation tasks state their own.

Live JEV authorization (maintainer, 2026-11-03)

The JEV leg is authorized: the model this spike specifies, a per-issue spend cap of $10, the maintainer's credential, run outside CI. The deliverable records the spend, the model version and sanitized results; no credential or account identifier appears in public evidence. If the cap is reached before the measurement is complete, stop and report what was measured.

Blocked by #3430

Triage 2026-11-03: verified the blocker (#3430 is open with needs: decision) and stated the ordering from epic #3428's breakdown; re-verified the G6 (:3760), G2 (:2395) and prepareOutwardPlan (:45) citations at 3d3516a02; added out of scope, acceptance criteria, verification and contract impact.

Triage 2026-11-03: folded the maintainer ruling (JEV leg authorized: spec'd model, $10 cap, maintainer credential, outside CI); removed needs: human; #3430 now ruled (ask) but not delivered, so still blocked.

Activity

  1. added
    type: spikeTime-boxed investigation. The deliverable is a written decision, not code.
    area: ui-sdkWire protocol, runtime schemas, the server and client SDK surfaces.
    area: ui-serverHono app factory: turn coordinator, auth, session catalog, routes, cron.
    priority: p2Wanted, not scheduled. Pulled in when a milestone has room.
    blockedWaiting on another issue or an upstream dependency. Say which in the body.
    on Nov 3, 2026
  2. added this to the 0.45.0 milestone on Nov 3, 2026
  3. added
    needs: humanWaiting on an action only a human can perform. State the required action in the issue.
    on Nov 3, 2026
  4. schlessera commented on Nov 3, 2026

    @schlessera
    OwnerAuthor

    Triage 2026-11-03: added needs: human. Measuring JEV needs live provider calls, and no recorded authorization covers this spike: the standing #838 authorization names only #923–#925. Needed: a maintainer comment here that either authorizes the JEV leg (model, spend cap, credential access) or rules the spike heuristics-only. Still blocked by #3430, which has needs: decision.

  5. added
    agent-readyContext and acceptance criteria are complete enough for an agent to take this unattended.
    and removed
    needs: humanWaiting on an action only a human can perform. State the required action in the issue.
    on Nov 3, 2026
  6. schlessera commented on Nov 3, 2026

    @schlessera
    OwnerAuthor

    Decision (maintainer, 2026-11-03): the JEV leg is authorized: the model the spike specifies, a per-issue spend cap of $10, the maintainer's credential, outside CI. Spend, model version and sanitized results are recorded in the deliverable. Removed needs: human; the body's prerequisite section now records the authorization, and there is an acceptance criterion for the cap. #3430 has been ruled (ask) but is not delivered, so blocked and Blocked by #3430 stay. Brief complete: agent-ready (blocked).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-readyContext and acceptance criteria are complete enough for an agent to take this unattended.area: ui-sdkWire protocol, runtime schemas, the server and client SDK surfaces.area: ui-serverHono app factory: turn coordinator, auth, session catalog, routes, cron.blockedWaiting on another issue or an upstream dependency. Say which in the body.priority: p2Wanted, not scheduled. Pulled in when a milestone has room.type: spikeTime-boxed investigation. The deliverable is a written decision, not code.

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions