Build1 publisher3 min readPublished
Agenthof rejects agent tool grants that name no tools when the config loads
Agenthof, an open-source governance layer for AI agents, now rejects any tool grant that names neither specific tools nor mode: all when its config loads. Its builder treats an empty allowlist as an error, since silent deny hides the mistake and silent allow-all grants tools nobody typed.
The Engineer · Build desk
Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

What happened
- The load error cites the offending line number and prints both fixes: list the tools the grant may call, or write mode: all.
- Roles open to everyone only through allowed_groups: ["*"], a role with no access floor is rejected, and executable allowlists follow the same rule.
- The post's author traces the same fail-open default to empty CORS origin lists, Kubernetes pods with no NetworkPolicy, and firewalls with rules commented out.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint A renamed key, dropped merge line or typo that leaves a tool grant empty now stops the config at load, so none of them can reach a running agent as full access.
- cost Operators whose configs still use bare tool entries must rewrite each one as mode: all or a named tool list before the config will load.
- decision Teams building agent allowlists have to pick among allow-all, silent deny and load-time rejection for an empty list; the post argues silent deny still leaves someone debugging a broken agent.
- capability The widest grant becomes a visible line in the diff, mode: all or ["*"], so a reviewer can question full access before it ships.
The failure starts in the loader. A config file says allowedTools while the parser reads allowed_tools, so the field someone wrote with care is never read and the default applies instead [8]. If that default is allow-all, the agent holds every tool on the server. The post's author, who builds Agenthof, an Apache-2.0 governance layer for AI agents written in Go [1], lists three other routes to the same result: a refactor that renames a key, a merge that drops a line from a list, and a config skeleton copied with the allowlist left for later [8]. "Every one of these looks fine in review," the author wrote [13].
The author calls this privilege by omission. According to the post, the same default shows up well outside agent tooling: empty CORS origin lists that reflect any origin, Kubernetes pods with no NetworkPolicy selecting them, and firewalls whose rules have been commented out [7].
The post argues that deny-by-default, the obvious correction, still hides the mistake. "Silently denying everything hides the mistake (now you're debugging why the agent won't work). Silently allowing everything is a hole," the author wrote [9]. Agenthof rejects the empty grant outright. "Rejecting it at load surfaces the mistake immediately, while the person who made it is still looking at the file," the post says [15]. The project's constitution states the rule directly: a grant that names no tools is rejected at apply and is never widened to the maximum [12].
The first thing the rule removed was a shorthand. A bare "- my-mcp" entry under tools used to grant every tool that server exposed [3]. Full access now has to be written as resource: my-mcp with mode: all, or narrowed to named tools, such as tools: [get_invoice] on a billing server [4]. A bare entry fails at load with an error that cites the line number and prints both fixes [5]. Roles work the same way. A role opens to everyone only through allowed_groups: ["*"], a role with no access floor is rejected, and executable allowlists follow the same rule [6].
I think reject-at-load is the right tradeoff for agent tool grants. My context: a person applies grants at a terminal, and an agent quietly holding an extra tool is harder to notice than one failing on a missing tool. The author puts the asymmetry plainly: "A too-small grant is a bug report. A too-large grant is an incident you find out about later, from someone else" [10].
The post's claim that under deny-by-default "someone notices in about five minutes" [11] is an estimate about someone else's workload. It transfers only if the denied tool gets called soon after deploy. A tool an agent reaches for once a month stays denied, and unnoticed, until that call. A load-time rejection fires before any traffic arrives.
The rule covers the lists the post names: tool grants, roles and executables [6]. The post did not disclose whether the loader also rejects unknown keys. Rejecting unknown keys would catch a misspelled field anywhere else in the config [8].
What to watch
- Whether Agenthof's loader also rejects unknown keys, closing the misspelled-field case outside tool, role and executable grants.
- Whether other agent frameworks and MCP clients adopt load-time rejection for empty tool lists or keep missing lists resolving to every tool.
- How Agenthof handles upgrades for existing configs that still carry bare tool entries.