anthropics / anthropics/claude-code
[BUG] sandbox.credentials.files protection can be bypassed on first access to a not-yet-existing deny-listed path
- Ngôn ngữ chính
- Python
- Star
- 145k
- Fork
- 23.1k
- Chỉ số merge pull request
- Chỉ số pull request đang chờ
Mô tả
### Preflight Checklist
- [x] I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
### What's Wrong?
**Environment:** Claude Code CLI 2.1.259, `sandbox.enabled: true`, `sandbox.enableWeakerNestedSandbox: true` (bubblewrap), running inside a Debian container itself running inside a macOS `container` VM.
**Config (managed-settings.json):**
```json
"sandbox": {
"credentials": {
"files": [
{ "path": "credentials.json", "mode": "deny" },
{ "path": "serviceAccountKey.json", "mode": "deny" },
{ "path": ".env", "mode": "deny" }
]
}
}
```
**Repro steps:**
1. In a directory with no `credentials.json` present, ask Claude to run via the Bash tool: `echo "hi" > credentials.json && cat credentials.json` **succeeds, discloses "hi"**. Identically reproduced with `serviceAccountKey.json` and `.env`.
2. Immediately after, ask Claude to run `cat credentials.json` (standalone) correctly **blocked**, `Permission denied`.
3. Ask Claude to run: `rm credentials.json` at this point fails with **`Device or resource busy`**, not `Permission denied` - the path is now an active mount point.
4. Deleting and recreating the file in a new invocation reproduces the bypass again on the same filename; the file is protected again on the very next invocation after that.
**Analysis:** Consistent with `sandbox.credentials.files` being enforced via a bind-mount established once per Bash-tool invocation, over whichever deny-listed paths already exist on disk at that moment (a bind-mount destination must pre-exist). A path that doesn't exist yet gets no mount for that invocation, so one compound command that creates and reads it slips through entirely.
**Impact:** Any deny-listed filename not yet present on disk can be created and read back in a single shell command, bypassing the protection on that first access - exactly the shape a prompt-injected instruction could exploit against a not-yet-created secrets file. Reproduced across three unrelated filenames, so this isn't file-specific.
### What Should Happen?
**Expected:** Protection shouldn't depend on whether the file existed before the sandboxed command started.
### Error Messages/Logs
```shell
```
### Steps to Reproduce
**Environment:** Claude Code CLI 2.1.259, `sandbox.enabled: true`, `sandbox.enableWeakerNestedSandbox: true` (bubblewrap), running inside a Debian container itself running inside a macOS `container` VM.
**Config (managed-settings.json):**
```json
"sandbox": {
"credentials": {
"files": [
{ "path": "credentials.json", "mode": "deny" },
{ "path": "serviceAccountKey.json", "mode": "deny" },
{ "path": ".env", "mode": "deny" }
]
}
}
```
**Repro steps:**
1. In a directory with no `credentials.json` present, ask Claude to run via the Bash tool: `echo "hi" > credentials.json && cat credentials.json` **succeeds, discloses "hi"**. Identically reproduced with `serviceAccountKey.json` and `.env`.
2. Immediately after, ask Claude to run `cat credentials.json` (standalone) correctly **blocked**, `Permission denied`.
3. Ask Claude to run: `rm credentials.json` at this point fails with **`Device or resource busy`**, not `Permission denied` - the path is now an active mount point.
4. Deleting and recreating the file in a new invocation reproduces the bypass again on the same filename; the file is protected again on the very next invocation after that.
**Analysis:** Consistent with `sandbox.credentials.files` being enforced via a bind-mount established once per Bash-tool invocation, over whichever deny-listed paths already exist on disk at that moment (a bind-mount destination must pre-exist). A path that doesn't exist yet gets no mount for that invocation, so one compound command that creates and reads it slips through entirely.
**Impact:** Any deny-listed filename not yet present on disk can be created and read back in a single shell command, bypassing the protection on that first access - exactly the shape a prompt-injected instruction could exploit against a not-yet-created secrets file. Reproduced across three unrelated filenames, so this isn't file-specific.
### Claude Model
Sonnet (default)
### Is this a regression?
I don't know
### Last Working Version
_No response_
### Claude Code Version
2.1.259 (Claude Code)
### Platform
Anthropic API
### Operating System
macOS
### Terminal/Shell
Terminal.app (macOS)
### Additional Information
_No response_
Hướng dẫn đóng góp
Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này
Hướng nghiên cứu
Start with the sandbox.credentials.files handling used when a Bash tool invocation begins, especially how deny-listed paths are handled when absent. Reproduce the issue with `echo "hi" > credentials.json && cat credentials.json` in a sandboxed invocation, then compare it with a standalone `cat`. Done means a newly created deny-listed path is protected during that first invocation and cannot be read back.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- linux, shell
- Lĩnh vực
- cli, operating-systems, security
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Sôi nổi
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 48/100