Skip to content

Sandbox can read Zero's own OAuth and provider credential stores #675

Description

@PierrunoYT

Summary

Sandboxed commands use a read-all/write-restricted filesystem posture, but the default credential deny list only covers ~/.aws, ~/.config/gcloud, ~/.azure, and the GOOGLE_APPLICATION_CREDENTIALS target. Zero's own credential-bearing files remain readable.

This exposes:

  • the default plaintext OAuth store at ~/.config/zero/oauth-tokens.json
  • credentials.json when plaintext provider-key storage is selected
  • both credentials.enc and its adjacent .secret AES key
  • user config.json, which can contain inline apiKey, authHeaderValue, and secret customHeaders

Relevant code

  • internal/sandbox/profile.go: permissionProfileReadRoots starts with the filesystem root; credentialDenyReadPaths does not include Zero files.
  • internal/oauth/store.go: the default storage case is the plaintext file backend.
  • internal/credstore/credstore.go: encrypted storage uses credentials.enc with securefile.NewCrypter(path + ".secret").
  • internal/config/types.go: provider profiles can persist inline keys and credential-bearing headers.

Observed at commit 6fc1220.

Impact

Environment scrubbing does not protect credentials stored on disk. Reading both the encrypted provider store and its co-located key is equivalent to reading plaintext.

Suggested fix

  1. Add exact default deny-read entries for user config.json, OAuth/MCP token stores, credentials.json, credentials.enc, and its .secret.
  2. Include overridden token-store locations.
  3. Add platform integration tests that attempt sandboxed reads of each store.

Activity

  1. added
    issue-approvedReviewed and approved by the core team; community PRs may implement this issue.
    on Jul 21, 2026
  2. Vasanthdev2004 commented on Jul 27, 2026

    @Vasanthdev2004
    Collaborator

    Fixed by #801, merged today. Verified against current main rather than inferred from the diff, driving credentialDenyReadPathsForEnvironment with the whole store materialised, since the builder filters to paths that exist:

    denied=true   ~/.config/zero/oauth-tokens.json
    denied=true   ~/.config/zero/credentials.json
    denied=true   ~/.config/zero/credentials.enc
    denied=true   ~/.config/zero/credentials.enc.secret
    denied=true   ~/.config/zero/config.json
    

    That is every file this issue named.

    The fix denies the directory rather than the individual files, which matters for the reason this issue exists. An earlier revision denied config.json alone, which is the one file in there that deliberately holds no secrets, while credentials.enc and its adjacent .secret key stayed readable together. Denying the directory also covers nested paths and files nobody enumerated, mcp-oauth-tokens.json among them.

    Two things this does NOT cover, both raised on the PR and both still open, so they should not be read as closed here: ~/.ssh, ~/.gnupg, ~/.git-credentials and ~/.config/git/credentials are all still readable by a sandboxed command. Worth its own issue if someone wants that boundary closed too.

    Also unchanged on Windows, where the deny list is skipped by design. #808 approaches that side differently, by giving the sandbox its own identity so the credential store is unreachable by construction rather than by enumeration.

  3. Vasanthdev2004 commented on Jul 27, 2026

    @Vasanthdev2004
    Collaborator

    Split out of here as #815, with the probe output and the git-config wrinkle written up. Flagging it on the PR thread too since @gnanam1990 raised these as the non-blocking remainder.

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

    issue-approvedReviewed and approved by the core team; community PRs may implement this issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions