Scoping settings.json for a New Contractor
A contractor is joining your team for two weeks to fix bugs in a
Node.js service. They'll use Claude Code daily. Someone on the team
suggests: "just add Bash(*) to the allowlist so they're not
constantly clicking through prompts — it's only two weeks."
- Explain concretely what
Bash(*)allows that the team probably didn't intend, using the actual matching behavior of permission rules. - Propose a narrower
permissionsblock (allowanddeny) that removes most of the prompt fatigue for routine bug-fixing work without granting blanket trust. - Name one additional layer, beyond
settings.jsonpermissions, that would catch a mistake even if the allowlist above were somehow too permissive.
1. What Bash(*) actually grants:
Permission rules match on the shell command's shape (a name plus a
prefix pattern), not on the intent behind it. Bash(*) matches every
possible Bash invocation — npm test and npm run lint, yes, but
also rm -rf, curl | bash, git push --force, and anything else the
agent might construct as a shell command in the course of a task. The
team wanted to stop approving routine test/lint commands; what they
actually did was remove the one human checkpoint on every irreversible
or externally-visible action a contractor's session could take,
intentionally or by mistake.
2. A narrower permissions block:
{
"permissions": {
"allow": [
"Bash(npm run test *)",
"Bash(npm run lint)",
"Bash(npm run build)",
"Bash(git diff *)",
"Bash(git status *)",
"Bash(git log *)"
],
"deny": [
"Bash(git push --force *)",
"Bash(rm -rf *)",
"Bash(curl *)",
"Read(./.env)",
"Read(./secrets/**)"
]
}
}
This allows exactly the read-only and routine build/test commands a bug-fixing task needs without a prompt each time, explicitly denies the destructive/network-reaching categories regardless of how a task is phrased, and leaves everything else — including commands nobody anticipated — falling back to an interactive prompt. That's the narrow-allow, explicit-deny pattern: scoped to trusted commands, not to the tool category that happens to contain them.
3. An additional layer:
A PreToolUse hook (or the sandbox) as a deterministic backstop —
for example, a hook that blocks any Bash command containing
--force or rm -rf regardless of what's in permissions.allow.
Unlike the allowlist, which is a static pattern match set up once, a
hook runs a real check on every call and isn't relying on someone
having anticipated every dangerous pattern in advance. Sandboxing is
the other option: it restricts what sandboxed commands can touch at
the OS level (filesystem and network), independent of what permission
rules say.
Share this question