cfgaudit

Rules / CFG006

CFG006 permissions.deny is absent or empty

Severity: warn OWASP: LLM03:2026 – Excessive Agency

What cfgaudit checks

cfgaudit flags any settings.json that defines a permissions block without a non-empty deny list. Without explicit denials, no rule blocks destructive operations such as rm -rf, git push --force, or arbitrary network calls — even when an allow entry is narrowly scoped, an unrelated default-allowed tool (or a future broadening of the allow list) can still reach them.

A denylist is the only mechanism that survives well-intentioned allow-list expansion, so it acts as a defense-in-depth guardrail rather than a primary control.

A deny list that is present in the file but not in force counts as absent. If the file carries a top-level value whose type the schema rejects, Claude Code discards the whole file (see CFG012), so its deny entries never load; CFG006 then fires and names the key responsible. The same applies to settings.local.json, which normally inherits the project deny list: when the project settings.json is discarded, there is nothing to inherit.

Trigger example

{
  "permissions": {
    "allow": ["Bash(make *)"]
  }
}

Safe alternative

{
  "permissions": {
    "allow": ["Bash(make *)"],
    "deny": [
      "Bash(rm *)",
      "Bash(git push --force*)",
      "Bash(curl *)",
      "Bash(wget *)"
    ]
  }
}

References

Documentation for cfgaudit 1.18.1. Source of this page · Rule implementation