From configure-plugin
Configures Claude Code security including permission wildcards, shell operator protections, and project-level allowlists. Use when auditing or hardening .claude/settings.json permissions.
How this skill is triggered — by the user, by Claude, or both
Slash command
/configure-plugin:claude-security-settingsThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
| Use this skill when... | Use `configure-claude-plugins` instead when... |
| Use this skill when... | Use configure-claude-plugins instead when... |
|---|---|
| You need the permission-wildcard syntax, shell-operator protections, and project-level allowlist patterns | You want to wire a project's .claude/settings.json to the marketplace and enable plugins end-to-end |
You are auditing or hardening an existing .claude/settings.json against the documented security conventions | You want runtime detection of marketplace enrollment and enabledPlugins before changing settings |
| Another skill needs to cite the canonical permission-wildcard reference | The user asked you to actually onboard a project to the laurigates/claude-plugins marketplace |
Expert knowledge for configuring Claude Code security and permissions.
Claude Code provides multiple layers of security:
| File | Scope | Priority |
|---|---|---|
~/.claude/settings.json | User-level (all projects) | Lowest |
.claude/settings.json | Project-level (committed) | Medium |
.claude/settings.local.json | Local project (gitignored) | Highest |
{
"permissions": {
"allow": [
"Bash(git status *)",
"Bash(npm run *)"
],
"deny": [
"Bash(rm -rf *)",
"Bash(sudo *)"
]
}
}
Bash(command *)
Bash() - Tool identifiercommand - Command prefix to match* - Wildcard suffix matching any arguments:ask suffix - Always prompt for user confirmation (e.g., Bash(git push *):ask)| Tier | Behavior | Example |
|---|---|---|
allow | Auto-allowed, no prompt | "allow": ["Bash(git status *)"] |
ask | Always prompts for confirmation | "allow": ["Bash(git push *):ask"] |
deny | Auto-denied, blocked | "deny": ["Bash(rm -rf *)"] |
| Pattern | Matches | Does NOT Match |
|---|---|---|
Bash(git *) | git status, git diff HEAD | git-lfs pull |
Bash(npm run *) | npm run test, npm run build | npm install |
Bash(gh pr *) | gh pr view 123, gh pr create | gh issue list |
Bash(./scripts/ *) | ./scripts/test.sh, ./scripts/build.sh | /scripts/other.sh |
Granular permissions:
{
"permissions": {
"allow": [
"Bash(git status *)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git add *)",
"Bash(git commit *)"
]
}
}
Tool-specific patterns:
{
"permissions": {
"allow": [
"Bash(bun test *)",
"Bash(bun run *)",
"Bash(biome check *)",
"Bash(prettier *)"
]
}
}
When a deny rule targets a specific flag (a force-push backstop is the canonical case), write it in space form — the trailing * enforces a word boundary, so the prefix must be followed by a space or end-of-string and the rule stops at the exact flag:
{
"permissions": {
"deny": [
"Bash(git push --force *)",
"Bash(git push -f *)"
]
}
}
Gotcha — colon form widens to longer flags. The
:*suffix ("Bash(git push --force:*)") has been observed prefix-matching the raw command string, so it also matchedgit push --force-with-lease …— silently hard-blocking the safe recovery form that stacked-PR workflows depend on. Deny rules cannot be overridden except viabypassPermissions, so the widening is a hard block, not a prompt (laurigates/claude-plugins#2038, caught in laurigates/loractl#39). Current official docs state an end-of-pattern:*is equivalent to the trailing space form, but the equivalence is not version-pinned in the changelog and the widening was observed in practice — the space form's word-boundary semantics are explicit, stable, and match what the permission dialog itself writes when you approve a prefix.
When auditing or generating deny entries, flag any entry ending in a flag followed by :* (e.g. --force:*, -f:*) and rewrite it to the space form.
Claude Code 2.1.7+ includes built-in protections against dangerous shell operators.
| Operator | Risk | Blocked Example |
|---|---|---|
&& | Command chaining | ls && rm -rf / |
|| | Conditional execution | false || malicious |
; | Command separation | safe; dangerous |
| | Piping | cat /etc/passwd | curl |
> / >> | Redirection | echo x > /etc/passwd |
$() | Command substitution | $(curl evil) |
` | Backtick substitution | `rm -rf /` |
When a command contains shell operators:
For legitimate compound commands, use scripts:
#!/bin/bash
# scripts/deploy.sh
npm test && npm run build && npm run deploy
Then allow the script:
{
"permissions": {
"allow": ["Bash(./scripts/deploy.sh *)"]
}
}
{
"permissions": {
"allow": [
"Bash(git status *)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git branch *)",
"Bash(npm list *)",
"Bash(bun pm ls *)"
]
}
}
{
"permissions": {
"allow": [
"Bash(git status *)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git branch *)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(git push *)",
"Bash(git pull *)",
"Bash(git fetch *)",
"Bash(git checkout *)",
"Bash(git merge *)",
"Bash(git rebase *)"
]
}
}
{
"permissions": {
"allow": [
"Bash(gh pr *)",
"Bash(gh run *)",
"Bash(gh issue *)",
"Bash(gh workflow *)"
]
}
}
{
"permissions": {
"allow": [
"Bash(bun test *)",
"Bash(npm test *)",
"Bash(vitest *)",
"Bash(jest *)",
"Bash(biome *)",
"Bash(eslint *)",
"Bash(prettier *)"
]
}
}
{
"permissions": {
"allow": [
"Bash(pre-commit *)",
"Bash(gitleaks *)",
"Bash(trivy *)"
]
}
}
mkdir -p .claude
cat > .claude/settings.json << 'EOF'
{
"permissions": {
"allow": [
"Bash(git status *)",
"Bash(git diff *)",
"Bash(npm run *)"
]
}
}
EOF
echo ".claude/settings.local.json" >> .gitignore
cat > .claude/settings.local.json << 'EOF'
{
"permissions": {
"allow": [
"Bash(docker *)"
]
}
}
EOF
| Context | Command |
|---|---|
| View project settings | cat .claude/settings.json | jq '.permissions' |
| View user settings | cat ~/.claude/settings.json | jq '.permissions' |
| Check merged permissions | Review effective settings in Claude Code |
| Validate JSON | cat .claude/settings.json | jq . |
Settings merge with this priority (highest wins):
.claude/settings.local.json (local).claude/settings.json (project)~/.claude/settings.json (user)| Syntax | Meaning |
|---|---|
Bash(cmd *) | Match cmd with any arguments |
Bash(cmd arg *) | Match cmd arg with any following |
Bash(./script.sh *) | Match specific script |
Block specific commands:
{
"permissions": {
"deny": [
"Bash(rm -rf *)",
"Bash(sudo *)",
"Bash(chmod 777 *)"
]
}
}
Flag-scoped deny rules (blocking a specific flag such as --force) must use the space form, never :* — see "Flag-Scoped Deny Rules: Use the Space Form" above.
| Error | Cause | Fix |
|---|---|---|
| Permission denied | Pattern doesn't match | Add more specific pattern |
| Shell operator blocked | Contains &&, |, etc. | Use script wrapper |
| Settings not applied | Wrong file location | Check path and syntax |
| JSON parse error | Invalid JSON | Validate with jq . |
Bash(git status *) over Bash&& and \| workflowsnpx claudepluginhub laurigates/claude-plugins --plugin configure-pluginExplains Claude Code settings hierarchy, permission wildcards, allow/deny patterns, and tool configurations. Use for setting up project permissions, debugging access issues, or understanding tool blocks.
Provides reference for Claude Code permission modes (default, acceptEdits, plan, dontAsk, bypass), allow/deny lists, pattern matching, and tool categories. Use to configure secure tool access and switch modes runtime.
Configures Claude Code permissions: tool rules (allow/deny/ask), modes (plan/dontAsk/bypass), sandboxing. Use for Bash/Edit/WebFetch policies, debugging prompts, org managed settings.