anthropics / anthropics/claude-agent-sdk-python
[SECURITY] Edit tool reads file content before PreToolUse hook validation, allowing content probing
- Lingua principale
- Python
- Stelle
- 8.1k
- Fork
- 1.3k
- Merge medio
- 2g 31m
- PR unite (30g)
- 1
Descrizione
## Summary
The Edit tool reads file content to validate `old_string` parameter **before** PreToolUse hooks are executed. This allows attackers to probe the content of files outside allowed directories by observing error messages, even when PreToolUse hooks are configured to block such access.
## Vulnerability Details
### Current Behavior
When an Edit operation is attempted with an `old_string` that:
1. Has multiple matches in the file → Returns "Found X matches" error
2. Does not exist in the file → Returns "String not found" error
**The file content is read before PreToolUse hooks can validate the file path.**
### Attack Vector
An attacker can probe file content outside allowed directories:
1. **Test for string existence**: Use `old_string="secret_api_key"` → If "String not found", the string doesn't exist; if "Found X matches", it does
2. **Enumerate file content**: Use common strings (`"password"`, `"token"`, `"key"`) to discover what's in the file
3. **Bypass security boundary**: Even though the edit is ultimately blocked, the information leak has already occurred
### Proof of Concept
1. Configure a PreToolUse hook to restrict file access to a specific directory:
```python
async def edit_only_cwd_hook(hook_input: HookInput, _session_id: str | None, _ctx: HookContext):
cwd = Path(hook_input["cwd"])
tool_input = hook_input.get("tool_input", {})
file_path_str = tool_input.get("file_path", "")
try:
file_path.relative_to(cwd)
except ValueError:
return SyncHookJSONOutput(decision="block", reason="...")
return SyncHookJSONOutput()
hooks = {
"PreToolUse": [
HookMatcher(matcher="Edit", hooks=[edit_only_cwd_hook])
]
}
```
2. Attempt to edit a file **outside** the allowed directory with a unique string:
```
Edit tool:
file_path: "/etc/passwd" (or any restricted file)
old_string: "root"
new_string: "hacked"
```
3. **Result**: Returns "Found X matches of the string to replace..." error
**The error message confirms the string "root" exists in the file, leaking information about file content.**
### Expected Behavior
PreToolUse hooks should be executed **before** any file content is read. The validation order should be:
1. ✅ PreToolUse hook validates file path
2. ✅ Hook blocks access to restricted paths
3. ❌ File content is never read (currently this happens before step 1)
## Security Impact
- **Information disclosure**: Attackers can probe file content character by character
- **Security boundary bypass**: Path-based access control is ineffective
- **Credential discovery**: Can detect presence of secrets, API keys, passwords in restricted files
## Affected Components
- Tool: `Edit`
- Hook Event: `PreToolUse`
- May also affect: `Write` (similar pattern)
## Environment
- Claude Code version 2.1.50
- Claude Agent SDK Version: 0.1.39
- Platform: macOS 26.3
## Related Issues (Claude Code Repository)
- [anthropics/claude-code#24908](https://github.com/anthropics/claude-code/issues/24908) - PostToolUse/PostToolUseFailure not fired for `` responses
- [anthropics/claude-code#21460](https://github.com/anthropics/claude-code/issues/21460) - PreToolUse hooks not enforced on subagent tool calls
## Suggested Fix
The PreToolUse hook should be triggered and validated **before** the Edit tool reads the file content. Only after the hook approves the operation should the file be accessed to validate `old_string`.
---
## Alternative: Temporary Workaround
For users affected by this issue, consider:
1. **Disable Edit tool entirely** - Only allow Write tool (may have similar issue, needs verification)
2. **Use MCP filesystem tools** with path restrictions instead of built-in tools
3. **Implement additional sandboxing** at the OS level (e.g., containerization)
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Valutazione
Questa issue non è ancora stata valutata.