Rules / CFG109
CFG109 a committed agent config file cannot be parsed
Severity: error
OWASP: LLM03:2026 – Excessive Agency
What cfgaudit checks
Every agent config surface cfgaudit reads — .claude/settings.json, .mcp.json, .codex/config.toml, .cursor/permissions.json, .zed/tasks.json and the rest — can fail to parse. CFG109 reports the file, names the parser's reason, and the scan continues over everything else in the repository.
The rule exists because of what it replaced. Until it was added, one unparseable config ended the whole scan:
$ cfgaudit .
cfgaudit: parse .codex/config.toml: toml: line 13 (last key "permissions.web_fetch_domains"):
type mismatch for parser.CodexPermissionProfile: expected table but found []any
exit 2
$ rm .codex/config.toml && cfgaudit .
.claude/settings.json [error] CFG004 defaultMode: bypassPermissions
.claude/settings.json [error] CFG001 Bash(rm -rf /) …
.claude/settings.json [error] CFG005 ANTHROPIC_BASE_URL → http://evil.example.com
CLAUDE.md:1:45 [error] CFG031 reads ~/.ssh/id_rsa
A file nobody was auditing hid four findings in files everybody was.
Why this is a finding rather than a fatal error
The agents do not stop either. Measured:
- Codex 0.156.1, handed a real corpus
.codex/config.tomlwhose[permissions]table holds a non-profile value, logsInvalid configuration; using defaultsand runs. - Claude Code 2.1.282, handed a
.claude/settings.jsonthat is not valid JSON, starts the session normally (aSessionStarthook in the user-scope file still fires).
A config layer that cannot be read is skipped, not fatal. So the honest report is about the file: it is committed, it does not parse, the settings it declares are not in force, and no rule that would read that surface ran over it. Error severity, because the scan of that surface is incomplete and what the repository declares is not what its readers get.
This is the same statement CFG012 makes for a settings.json that Claude Code discards over a top-level type mismatch. The difference is who rejects the file: there the agent parses it and drops it, here cfgaudit cannot read it at all.
Trigger example
# .codex/config.toml
[permissions]
web_fetch_domains = ["example.com"] # the table takes profile tables, not values
→ error, naming the file and the parser's message.
Not covered
An empty or whitespace-only repository-root .mcp.json is not reported: it declares no servers, and Claude Code 2.1.299 stopped reporting it as invalid (claude mcp list shows no error).
cfgaudit's own inputs stay fatal. A .cfgauditignore or .cfgaudit.yml that does not parse changes what cfgaudit itself does — which rules run, what is suppressed — so continuing with a half-read configuration would make every other finding unreliable.
Safe alternative
Fix the file so the agent reads it, or delete it. If it belongs to a different tool and happens to sit at an agent's config path, move it: that path is read by the agent whatever the file was meant for.
Documentation for cfgaudit 1.18.1. Source of this page · Rule implementation