Skip to content

Adopt nono's phantom-token credential-proxy pattern for Phase-1 broker-not-mount #121

Description

@rappdw

Follow-up to the milestone-#12 evaluation (docs/security/CREDENTIAL_BROKER_EVALUATION.md), informed by nolabs-ai/nono — a shipped reference implementation of broker-not-mount (see docs/security/nono-comparison.md).

The borrow

nono keeps the real credential out of the sandbox entirely via a localhost reverse proxy + phantom token:

  • Agent gets a per-session 256-bit phantom token (NONO_PROXY_TOKEN), never the real key.
  • Agent calls http://127.0.0.1:<port>/<service>/...; the proxy validates the phantom token, swaps in the real credential, forwards over TLS. SDKs steered via OPENAI_BASE_URL/ANTHROPIC_BASE_URL — no agent code change.
  • cmd:// lazy host-side capture: durable creds (e.g. gh auth token, an OAuth refresh) run on the host on first use, cached with a TTL; the sandbox only ever sees the phantom token.
  • L7 endpoint_rules scope a credential to specific method+path (closes exfil-to-allowed-host, THREAT_MODEL R3).

This is concretely sandy's eval A1 (durable cred stays host-side) and A2 (proxy-side injection). It also confirms the eval's central trade-off: to inject at the proxy you must terminate TLS — nono's proxy is TLS-terminating, whereas sandy's egress proxy is deliberately passthrough (proxy/config.go "never terminate"). So this is not a free extension of the existing sidecar; it's the deliberate no-MITM-invariant fork the eval's A2 describes.

Scope for this issue (Phase-1 slice)

  1. Spike a host-side credential broker exposing a localhost endpoint the container reaches (through the existing egress-proxy topology or a dedicated localhost forward), handing the container a phantom/short-lived token, not the raw key.
  2. cmd://-style capture for the durable credential (start with gh auth token and the Claude/Gemini OAuth refresh-token → short-lived access-token case the eval's A1 already identified as the highest-value, no-provider-cooperation win).
  3. Decide the injection point: A1 (broker hands a short-lived token in, agent still makes the request) vs A2 (proxy injects, agent never holds it → requires the TLS-terminating fork). A1 first.
  4. Record the resolved posture (which creds brokered vs. still mounted) in sandy-session.json, mirroring the effort field.

Explicitly out of scope (track separately)

  • nono's isolation primitive (Landlock/seccomp-notify) — sandy's container is the stronger boundary; borrow the credential layer only.
  • Full SPIFFE/per-tool child sandboxes — longer-horizon.

References

  • docs/security/nono-comparison.md, docs/security/CREDENTIAL_BROKER_EVALUATION.md (A1/A2), research/credential-broker-cb4a.md.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions