Skip to content

fix(permissions): flag wildcard and case-variant dangerous tool grants#32

Open
dmchaledev wants to merge 1 commit into
mainfrom
claude/amazing-franklin-jo7xav
Open

fix(permissions): flag wildcard and case-variant dangerous tool grants#32
dmchaledev wants to merge 1 commit into
mainfrom
claude/amazing-franklin-jo7xav

Conversation

@dmchaledev

Copy link
Copy Markdown
Contributor

Summary

A HIGH-severity false negative in the tool-permission rules: a grant that is strictly broader than a listed dangerous permission slips through, and the whole scan reports PASSED. The matching in OVERPRIVILEGED_TOOL (src/rules/config-rules.ts) and UNRESTRICTED_FILE_ACCESS (src/rules/runtime-rules.ts) was exact-string and case-sensitive:

// OVERPRIVILEGED_TOOL
const matched = tool.permissions.filter((p) => DANGEROUS_PERMISSIONS.includes(p));
// UNRESTRICTED_FILE_ACCESS
const hasWildcard = perms.includes('filesystem:*'); // never normalized

So a tool granted the broadest possible permissions is not flagged:

permissions meaning before after
["*"] grants everything, incl. shell:exec ❌ missed ✅ flagged
["shell:*"] every shell action (⊇ shell:exec) ❌ missed ✅ flagged
["SHELL:EXEC"] shell:exec, different case ❌ missed ✅ flagged
["filesystem:*"] full filesystem (⊇ filesystem:write) ⚠️ caught only by UNRESTRICTED_FILE_ACCESS, not OVERPRIVILEGED_TOOL ✅ both

Repro (built CLI at current main)

// wild.json — a tool with global "*" permissions
{ "transport": { "url": "https://x.example.com", "tls": true,
    "auth": { "type": "bearer", "token": "abcdefghijklmnopqrstuvwxyz0123456789abcd" } },
  "rateLimit": { "enabled": true },
  "tools": [ { "name": "god-tool", "permissions": ["*"] } ] }
$ node dist/cli.js wild.json --format=table
Found 0 finding(s): 0 critical, 0 high, 0 medium, 0 low
PASSED          # ← a tool granted EVERY permission passes the gate

For a tool sold as a CI/CD security gate, a maximally-overprivileged tool passing silently is exactly the class of misconfiguration this scanner exists to catch.

Fix

  • OVERPRIVILEGED_TOOL — a granted permission now matches a dangerous one when it is an exact match, a global *, or a category wildcard that subsumes it (shell:* covers shell:exec). Comparison is case-insensitive. Evidence still reports the granted permission in its original spelling, so * / shell:* surface in the finding.
  • UNRESTRICTED_FILE_ACCESS — normalize case and treat a global * as full filesystem access, alongside the existing filesystem:* / read+write logic.

The change is localized to the two rules; the parser, scorer, and report shape are untouched. Detection only widens to subsuming grants — no rule fires on anything narrower than before, so there are no new false positives (the unrelated logging:* case is covered by a negative test).

Verification

  • npm run typecheck ✓ · npm run lint (0 warnings) ✓ · npm test127 passed, 5 suites ✓ · npm run build
  • wild.json repro now correctly FAILS (* and shell:* flagged).
  • examples/secure-config.json → still PASSED (no false positive).
  • examples/vulnerable-config.json → still FAILED (the filesystem:* tool is now also correctly flagged OVERPRIVILEGED_TOOL).
  • 9 new regression tests: global/category wildcards, case variants, and negatives (read-only, unrelated-category wildcard). UNRESTRICTED_FILE_ACCESS previously had no dedicated test block — one is added.

Why this isn't a duplicate

None of the open issues (#11, #19, #26, #27) or open PRs (secrets #28/#29, traversal #31, TLS #18, --rule #17/#25, CI #12/#20, docs) touch permission matching — they concern auth, transport, output paths, secrets, YAML, CLI, and CI. This closes a distinct false-negative class in the permission rules.

Acceptance criteria

  • A tool with ["*"] or ["shell:*"] is flagged OVERPRIVILEGED_TOOL.
  • Permission matching is case-insensitive (SHELL:EXEC fires).
  • ["*"] and filesystem:* are flagged UNRESTRICTED_FILE_ACCESS.
  • No new false positives (read-only and unrelated-category wildcard do not fire; secure example still passes).
  • Regression tests covering the wildcard, case, and negative cases.

🤖 Generated with Claude Code

https://claude.ai/code/session_013AmKB9ALSPnXTJsSMqvVhJ


Generated by Claude Code

OVERPRIVILEGED_TOOL and UNRESTRICTED_FILE_ACCESS matched permission
strings exactly and case-sensitively, so a grant strictly broader than a
listed dangerous permission slipped through — and the whole scan reported
PASSED. A tool with "permissions": ["*"] (grants everything), "shell:*"
(broader than shell:exec), or "SHELL:EXEC" (case variant) produced no
finding.

For a CI/CD security gate, missing a maximally-overprivileged tool is a
meaningful false negative. Fix:

- OVERPRIVILEGED_TOOL: match a dangerous permission when the granted
  permission is an exact match, a global "*", or a category wildcard
  (e.g. shell:* covers shell:exec). Comparison is case-insensitive.
  Evidence reports the granted permission (original spelling) that fired.
- UNRESTRICTED_FILE_ACCESS: normalize case and treat a global "*" as full
  filesystem access alongside the existing filesystem:* / read+write logic.

Regression tests cover global/category wildcards, case variants, and
negative cases (read-only, unrelated category wildcard). All 127 tests,
typecheck, and lint pass; secure example still PASSES (no false positive),
vulnerable example still FAILED.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013AmKB9ALSPnXTJsSMqvVhJ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants