This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/magpie.git


The following commit(s) were added to refs/heads/main by this push:
     new dd107da  feat(agent-isolation): protect secret env vars via 
sandbox.credentials (#591)
dd107da is described below

commit dd107dafc3e71f1382bb923784ece83109e5ce88
Author: Jarek Potiuk <[email protected]>
AuthorDate: Sat Jun 27 15:55:05 2026 -0400

    feat(agent-isolation): protect secret env vars via sandbox.credentials 
(#591)
    
    * feat(agent-isolation): protect secret env vars via sandbox.credentials
    
    Add a `sandbox.credentials.envVars` block (claude-code 2.1.187+) to
    the dogfooded `.claude/settings.json`, with `mode: "deny"` for the
    secret environment variables a sandboxed command could otherwise
    read.
    
    This closes a real gap: `sandbox.filesystem.denyRead` and the
    `permissions.deny[Read(...)]` rules are filesystem-only and do NOT
    stop a sandboxed Bash command from reading `$ANTHROPIC_API_KEY`,
    `$GH_TOKEN`, or dumping `env`. `sandbox.credentials.envVars` is the
    only layer that covers environment variables.
    
    `mode: "deny"` unsets the variable for sandboxed commands only — the
    unsandboxed agent process keeps its own auth, and sandbox-bypassed
    commands (e.g. `gh`, which authenticates via ~/.config/gh) are
    unaffected. Credential FILES are already covered by
    `denyRead: ["~/"]`, so only `envVars` is added.
    
    The annotated copy in docs/setup/secure-agent-setup.md is updated to
    match, documenting the env-var gap and the deny-vs-mask choice.
    
    Generated-by: Claude Code (Opus 4.8)
    
    * fix(sandbox-lint): mirror sandbox.credentials into expected.json baseline
    
    The `lint .claude/settings.json against baseline` CI check (sandbox-lint,
    threat-model mitigation M.29) requires every change to the live sandbox
    config to be mirrored in tools/sandbox-lint/expected.json. The previous
    commit added `$.sandbox.credentials` to .claude/settings.json but not to
    the baseline, so the check failed with:
    
      $.sandbox.credentials: extra in settings (not in expected)
    
    Mirror the same `credentials.envVars` block into the baseline. `uv run
    sandbox-lint` now passes.
    
    Generated-by: Claude Code (Opus 4.8)
---
 .claude/settings.json            | 14 ++++++++++++++
 docs/setup/secure-agent-setup.md | 25 +++++++++++++++++++++++++
 tools/sandbox-lint/expected.json | 14 ++++++++++++++
 3 files changed, 53 insertions(+)

diff --git a/.claude/settings.json b/.claude/settings.json
index 39ae34e..6dd439f 100644
--- a/.claude/settings.json
+++ b/.claude/settings.json
@@ -46,6 +46,20 @@
         "*.crates.io"
       ],
       "enableWeakerNetworkIsolation": true
+    },
+    "credentials": {
+      "envVars": [
+        { "name": "ANTHROPIC_API_KEY", "mode": "deny" },
+        { "name": "ANTHROPIC_AUTH_TOKEN", "mode": "deny" },
+        { "name": "CLAUDE_CODE_OAUTH_TOKEN", "mode": "deny" },
+        { "name": "GH_TOKEN", "mode": "deny" },
+        { "name": "GITHUB_TOKEN", "mode": "deny" },
+        { "name": "AWS_ACCESS_KEY_ID", "mode": "deny" },
+        { "name": "AWS_SECRET_ACCESS_KEY", "mode": "deny" },
+        { "name": "AWS_SESSION_TOKEN", "mode": "deny" },
+        { "name": "NPM_TOKEN", "mode": "deny" },
+        { "name": "TWINE_PASSWORD", "mode": "deny" }
+      ]
     }
   },
   "permissions": {
diff --git a/docs/setup/secure-agent-setup.md b/docs/setup/secure-agent-setup.md
index dc29d7e..177c89b 100644
--- a/docs/setup/secure-agent-setup.md
+++ b/docs/setup/secure-agent-setup.md
@@ -427,6 +427,31 @@ below, annotated.
       // data-exfiltration vector through the trustd service." No-op
       // outside the sandbox (e.g. CI). macOS-only.
       "enableWeakerNetworkIsolation": true
+    },
+    // `sandbox.credentials` (claude-code 2.1.187+) is the only layer
+    // that protects secret ENVIRONMENT VARIABLES — `denyRead` and the
+    // `permissions.deny[Read(...)]` rules are filesystem-only and do
+    // NOT stop a sandboxed command from reading `$ANTHROPIC_API_KEY`
+    // or dumping `env`. `mode: "deny"` unsets the var for sandboxed
+    // commands only; the unsandboxed agent process keeps its own auth,
+    // and sandbox-bypassed commands (e.g. `gh`, which reads
+    // ~/.config/gh) are unaffected. Credential FILES are already
+    // covered by `denyRead: ["~/"]`, so only `envVars` is listed here.
+    // (`mode: "mask"` + `injectHosts` is the alternative: keep the var
+    // usable only for connections to named hosts — not needed here.)
+    "credentials": {
+      "envVars": [
+        { "name": "ANTHROPIC_API_KEY", "mode": "deny" },
+        { "name": "ANTHROPIC_AUTH_TOKEN", "mode": "deny" },
+        { "name": "CLAUDE_CODE_OAUTH_TOKEN", "mode": "deny" },
+        { "name": "GH_TOKEN", "mode": "deny" },
+        { "name": "GITHUB_TOKEN", "mode": "deny" },
+        { "name": "AWS_ACCESS_KEY_ID", "mode": "deny" },
+        { "name": "AWS_SECRET_ACCESS_KEY", "mode": "deny" },
+        { "name": "AWS_SESSION_TOKEN", "mode": "deny" },
+        { "name": "NPM_TOKEN", "mode": "deny" },
+        { "name": "TWINE_PASSWORD", "mode": "deny" }
+      ]
     }
   },
   "permissions": {
diff --git a/tools/sandbox-lint/expected.json b/tools/sandbox-lint/expected.json
index 39ae34e..6dd439f 100644
--- a/tools/sandbox-lint/expected.json
+++ b/tools/sandbox-lint/expected.json
@@ -46,6 +46,20 @@
         "*.crates.io"
       ],
       "enableWeakerNetworkIsolation": true
+    },
+    "credentials": {
+      "envVars": [
+        { "name": "ANTHROPIC_API_KEY", "mode": "deny" },
+        { "name": "ANTHROPIC_AUTH_TOKEN", "mode": "deny" },
+        { "name": "CLAUDE_CODE_OAUTH_TOKEN", "mode": "deny" },
+        { "name": "GH_TOKEN", "mode": "deny" },
+        { "name": "GITHUB_TOKEN", "mode": "deny" },
+        { "name": "AWS_ACCESS_KEY_ID", "mode": "deny" },
+        { "name": "AWS_SECRET_ACCESS_KEY", "mode": "deny" },
+        { "name": "AWS_SESSION_TOKEN", "mode": "deny" },
+        { "name": "NPM_TOKEN", "mode": "deny" },
+        { "name": "TWINE_PASSWORD", "mode": "deny" }
+      ]
     }
   },
   "permissions": {

Reply via email to