cfgaudit

Rules / CFG043

CFG043 permissions.deny does not restrict cloud provider credential files

Severity: error OWASP: LLM02:2026 – Sensitive Information Disclosure

What cfgaudit checks

Cloud provider credential files grant programmatic access to infrastructure. cfgaudit flags a permissions.deny block that exists but does not cover the well-known credential paths for one or more providers:

Provider Paths
AWS **/.aws/credentials, **/.aws/config
GCP **/.config/gcloud/, **/application_default_credentials.json
Azure **/.azure/, **/.azure/accessTokens.json

At least one pattern per provider must be present; a broad pattern like Read(~/.aws/*) counts as covering AWS. The finding lists exactly which providers are uncovered. A completely absent permissions.deny block is reported by CFG006.

A deny-all entry suppresses this finding entirely: Read(*) / Read(**) / Read(**/*) (any version), or the bare "*" deny-all-tools glob on Claude Code ≥ 2.1.166 (a no-op on older releases, so the finding still fires there; treated as covering when the version is unknown).

Trigger example

{
  "permissions": {
    "deny": ["Read(.env)", "Read(**/.aws/credentials)"]
  }
}

→ error (GCP and Azure still uncovered).

Safe alternative

Cloud credentials live in the home directory, so the pattern has to be anchored at the filesystem root with //. A bare **/ pattern is anchored at the working directory and reaches only a copy of the directory inside the repository; see CFG044 for the measurement.

{
  "permissions": {
    "deny": [
      "Read(//**/.aws/credentials)",
      "Read(//**/.aws/config)",
      "Read(//**/.config/gcloud/**)",
      "Read(//**/application_default_credentials.json)",
      "Read(//**/.azure/**)"
    ]
  }
}

References

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