aws / aws/agent-toolkit-for-aws
aws-core: secret-safety hook does not block GetSecretValue issued through aws___run_script (the path asm-exec uses)
- Dominant language
- Python
- Stars
- 2.6k
- Forks
- 306
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 51
Description
**Component:** `plugins/aws-core/com.anthropic.claude-code/hooks/secret-safety.py`
## Summary
The aws-core PreToolUse hook is documented as blocking `GetSecretValue` "via MCP tools or structured AWS API calls". It does block the AWS CLI shape, inline SDK method calls, and the localhost:2773 daemon URL. It does not block the one MCP shape that actually fetches secrets on the current server: a `run_script` body that calls `call_boto3(service_name="secretsmanager", operation_name="GetSecretValue", ...)`. Since `aws___call_aws` was removed and `asm-exec` moved to `run_script` (#296), this is the primary programmatic path to a secret value, and it passes the hook unchanged.
## Reproduction
Pipe this PreToolUse payload into the hook exactly as `hooks.json` invokes it:
```json
{"tool_name": "mcp__aws-mcp__aws___run_script",
"tool_input": {"code": "result = await call_boto3(service_name=\"secretsmanager\", operation_name=\"GetSecretValue\", params={\"SecretId\": \"x\"})\nresult"}}
```
Expected: a deny decision. Observed: empty stdout, exit 0 (allowed). The same payload with `operation_name="get-secret-value"` or `"BatchGetSecretValue"` is also allowed. For comparison, the Bash payload `aws secretsmanager get-secret-value --secret-id x` is correctly denied.
Reproduced 2026-09-09 on Windows 11 with Python 3.14, aws-core 1.1.0 as pinned by `claude-plugins-official` (toolkit commit 08ad220e). The hook file at `main` (df5d2e84) is byte-identical, so the gap is present upstream too.
## Root cause
Two independent problems in `secret-safety.py`:
1. **Unreachable `run_script` branch.** `main()` first tests `tool_name.startswith("mcp__")` and that branch always terminates with `allow()` (a `sys.exit`). Every MCP tool name starts with `mcp__`, so the later `if "run_script" in tool_name:` branch can never execute for an MCP tool. It is effectively dead code.
2. **Operation detection needs a call parenthesis.** Even within the `mcp__` branch, the structured check reads `service_name` / `operation_name` from the top level of `tool_input`, which `run_script` does not have (it has `code`). The fallback `SDK_CALL_PATTERN` requires `get_secret_value(`, `GetSecretValueCommand(`, or `GetSecretValue(Request|Command)?(`. The boto3-kwargs form used by `call_boto3` is `operation_name="GetSecretValue", params=`, which has no parenthesis after the operation name and so never matches. `CLI_GSV_PATTERN` does not apply either because there is no `aws secretsmanager` prefix.
## Suggested fix
- Move the `run_script` check ahead of, or fold it into, the `mcp__` branch so it runs for `mcp__*run_script*` tool names.
- Detect the operation independent of call syntax. A conservative rule that covers boto3 kwargs, the CLI string, SDK method calls, and JS command classes without false positives: normalize each string in `tool_input` (lowercase, strip `-` and `_`) and deny when it contains both `getsecretvalue` and `secretsmanager`. Requiring both tokens avoids denying a script that merely mentions the operation name for another service.
- Add these payloads to the hook's tests: `run_script` with `operation_name="GetSecretValue"`, with `"get-secret-value"`, with `"BatchGetSecretValue"`, and a `DescribeSecret` control that must stay allowed.
A minimal user-level supplementary hook implementing the normalized-token rule has been running on my side since 2026-09-09 and passes those cases; happy to turn it into a PR against `secret-safety.py` if the approach is acceptable.
## Related, out of scope here
The `claude-plugins-official` marketplace still pins aws-core at 08ad220e (2026-09-03), which ships the pre-#296 `asm-exec` calling the removed `aws___call_aws`. On that build every `{{resolve:...}}` fails silently with "Failed to resolve" (the server answers `-32600 The call_aws tool has been removed`). That is a marketplace-pin lag rather than a toolkit bug, but users installing today get a non-working `asm-exec` alongside this hook gap.
Contributor guide
Research direction
Start with plugins/aws-core/com.anthropic.claude-code/hooks/secret-safety.py and reproduce the provided mcp__aws-mcp__aws___run_script payload through the hook as hooks.json invokes it. Trace the mcp__ and run_script handling, then add the listed run_script cases and the DescribeSecret control to the hook's tests. Done means secret-fetching run_script payloads are denied while the control remains allowed, alongside the existing AWS CLI behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, python
- Domain
- security, tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100