Claude Code’s Managed-Settings Bug Is a Security Boundary Wearing a Config Hat
A security boundary that disappears quietly is worse than one that fails loudly. The new Claude Code report about Linux managed settings is not interesting because JSON precedence is inherently thrilling — it is interesting because the affected layer is supposed to be the boring, administrator-owned place where “no” actually means no.
The issue, filed against Anthropic’s Claude Code repository on June 23, describes a RHEL 9 environment where facility-level policy in /etc/claude-code/managed-settings.json appears to load and then gets overwritten by an empty server-managed policy response. The reported debug trace shows local MDM settings being read, remote managed settings being loaded, and then policySettings destinations for permissions.allow and permissions.deny ending up as 0 rule(s): []. That is the bad version of success: the file exists, the runtime sees it, and the safety control still vanishes before it matters.
The concrete example is the kind enterprise operators should recognize immediately. The reporter’s local policy allowed commands such as Bash(pixi*), Bash(du*), and Bash(df*), while denying Bash(condor_*). In a shared compute environment, that makes sense. You may want developers or researchers to use Claude Code for local refactors, documentation, inspection, or lightweight scripting, while preventing the agent from submitting or manipulating HTCondor jobs. The human still has their shell privileges. The agent gets a narrower operating envelope.
If the report is accurate, that envelope can be erased by an empty remote policy cache. That is not a preference bug. It is a host-policy integrity bug.
The host policy has to be the floor, not a suggestion
Claude Code’s settings documentation describes managed settings as the highest-priority scope for security policies and compliance requirements. That is exactly the promise administrators rely on when they allow coding agents onto machines they do not fully trust. A developer’s local settings can be flexible. A project’s settings can be collaborative. But a machine owner’s managed policy has to be treated like infrastructure, not UI state.
The tricky part is that “managed” now has multiple possible owners. There is the user’s Anthropic organization, which may define enterprise policy. There is also the machine owner, which may be a company IT team, a university HPC facility, a lab administrator, or a security team responsible for a shared workstation fleet. Those are not interchangeable authorities. An empty remote organization policy should not mean “delete the host’s local deny list.” The safer composition rule is boring: local host denies should union upward, remote policy can add restrictions, and absence of remote restrictions should not remove the local floor.
This is the same class of design problem cloud IAM solved the hard way. When multiple policy sources exist, empty policy is not the same thing as explicit allow, and a higher-level management plane cannot casually erase a lower-level safety boundary without a visible audit trail. Coding agents need the same discipline because their tools are not just chat features. They are execution paths.
The reported community reaction was thin at research time: two comments, no reactions, and no Hacker News thread found for targeted searches. That does not reduce severity. Enterprise agent bugs often start as quiet operator reports because the people most affected are not farming screenshots. They are trying to keep a shared system from turning into an incident report.
Do not test policy by reading the policy file
The practitioner mistake here would be to verify that managed-settings.json is syntactically valid and call the environment governed. A valid file is only an input. The real control is runtime behavior. If you operate Claude Code on shared machines, the test should be executable: start a fresh session, attempt a harmless command that matches each critical deny rule, confirm Claude Code blocks it, and save the evidence with the CLI version and timestamp.
For a deny rule such as Bash(condor_*), that canary can be a no-op or intentionally invalid command name that still matches the permission pattern. The point is not to run a dangerous command. The point is to prove the permission engine sees the same rule the administrator believes it configured. If the canary passes through, stop treating the session as governed and fall back to outer controls: shell wrappers, AppArmor or SELinux policy, containerization, separate service accounts, or simply banning agent use on that host class until the boundary is trustworthy.
Teams should also archive startup diagnostics, but logs are not enough if the log can say “loaded” before a later source overwrites the result. The minimum useful check is post-merge effective policy. Better would be a first-class Claude Code command that prints the effective permission graph by source: host managed policy, org managed policy, project settings, user settings, command-line flags, and the final allow/deny decision for a proposed tool call. Security software should not require archaeology to answer “why was this Bash command allowed?”
There is a product lesson for Anthropic as well. If managed settings are positioned as an administrative security layer, the runtime should fail closed when that layer is ambiguous. If local managed policy loads and remote policy returns an empty response, the safe behavior is not to silently collapse to zero rules. At minimum, Claude Code should emit a conspicuous warning that one managed source replaced another. Better: deny rules from host-managed policy should survive empty remote state unless an explicit, authenticated, auditable override says otherwise.
The broader agent-security conversation has been too focused on prompt injection and not focused enough on mundane enforcement paths. Prompt injection matters. Approval prompts matter. But none of that helps if the configuration layer that defines the permission boundary can be nullified by precedence semantics. A coding agent is only as safe as the most boring part of its control plane.
My take: this is exactly the kind of bug that separates hobbyist agent setups from deployable ones. Shared infrastructure does not need a model that promises to behave. It needs a runtime that proves the host’s “no” survived startup. Until that is boring, managed settings are a security boundary wearing a config hat.
Sources: Anthropic Claude Code issue #70181, Claude Code settings documentation, Claude Code permissions documentation, Claude Code hooks reference