Skip to content

The consent guarantee README states unconditionally is enforced on one of two transports #187

Description

@macanderson

README states the consent guarantee unconditionally; the spec enforces it on one transport. On stdio — the primary binding, the one every reference provider and all four SDKs use — a provider that sends workspace content to the internet while declaring egress: false is never detected, and the host queries it without ever asking the user.

In plain words

The README tells readers, unconditionally, "a provider that sends your data off-machine is never queried without your permission." That is only true for network (HTTP) providers. For local (stdio) providers — the kind every reference provider and every SDK actually uses today — nothing watches whether the provider opens a socket and phones home, so a misbehaving stdio provider can exfiltrate workspace content with zero consent prompt and zero detection.

README.md, in the seven-guarantees table:

Consent enforcement — A provider that sends data off-machine is never queried until you record named, revocable consent. The query payload is not transmitted first.

The spec is considerably more careful, and the gap between them is the whole issue:

  • C3: "A provider SHOULD declare egress: true honestly if data leaves the machine, directly or indirectly." Marked advisory in the Verified-by column.
  • C4: "A host's HTTP transport MUST treat every non-loopback provider as egress regardless of its handshake claim."

§4 then says exactly why C4 exists: "C3 is a claim, and a protocol that trusted claims about egress would have no security story at all. The transport overrides the declaration because the transport knows." That reasoning is correct, and it is the argument for why the stdio case is a hole rather than a gap — over stdio the transport does not know, so the only thing standing between workspace content and the network is C3, the advisory SHOULD the same paragraph says a protocol cannot rely on.

A stdio provider is a child process with a socket. Nothing in the protocol, the host, or the conformance suite observes whether it opens one.

The loopback case makes it concrete

Even on HTTP, C4 exempts loopback. A provider listening on 127.0.0.1 is classified local and can proxy every query straight out. (The reference host is stricter than C4 here — http.rs forces egress = true for all HTTP providers including loopback — which is the right call and is itself undocumented as a deliberate divergence from the spec's text.)

So the enforced guarantee is: a host will not send a payload to a non-loopback HTTP endpoint without consent. The claimed guarantee is: a provider that sends data off-machine is never queried without consent. The second is not a stronger statement of the first; it is a different statement, about a property no transport can observe.

Why this is worth an issue rather than a README edit

Four things need to move together, and the wording of the guarantee depends on which of them the project wants:

  1. The claim. README needs to say what is enforced. But the honest sentence depends on (2)–(4), so editing it alone risks understating a guarantee that is about to get stronger.
  2. Whether stdio gets a sandbox story. stdio.rs already spawns children with a scrubbed environment (there is a test for it). Network confinement for a child process is platform-specific — a sandbox profile on macOS, a namespace on Linux — and whether the reference host takes that on is a scope decision, not a patch.
  3. Whether egress should be attestable. §11.1 lists what is "genuinely unchecked" and is scrupulous about it; the stdio egress hole is not on that list, and it is a larger hole than the three that are.
  4. Whether C3 should be MUST. It cannot be checked either way, but a MUST makes a dishonest declaration a conformance violation a deployment can act on contractually, which is how every other unverifiable-but-load-bearing declaration in the industry is handled.

Pillar

Reliability. The seven guarantees are the protocol's entire claim on a reader's trust, and README calls the combination load-bearing: "Remove any one and the trust model collapses back to the blob-pipe." A guarantee that holds on one of two bindings should not be stated as holding on both, in the document most people read first.

Done looks like

  • README's consent row states the enforced property and names the transport it binds, in the register §4 already uses.
  • §11.1 gains the stdio egress hole in its What remains genuinely unchecked list, beside C4/C7/C8 — the section exists precisely so a suite "that quietly omitted the rules it cannot check" is not what this project ships.
  • A decision recorded on C3's strength and on whether child-process network confinement is in scope for the reference host.
  • The reference host's stricter-than-C4 treatment of loopback HTTP documented as deliberate, so it is not read as a bug and relaxed later.
  • A witness for the gap itself: a test (or documented manual repro) showing a stdio provider opening an outbound connection while declaring egress: false goes undetected today, so a future fix — sandboxing, or a MUST-strength C3 — has a fail→pass case to prove against.
  • Any new SPEC.md/README prose this produces cites code by symbol (Host::add_stdio, stdio.rs, http.rs's loopback handling) rather than a pinned line number, matching this org's citation convention.
  • Lands as a SPEC.md/README update plus any host-side detection code in the crate that already owns transport classification (contextgraph-host), without growing a file past this workspace's size conventions.

Activity

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

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions