Model-designed 'block all' admin switch silently overridden by per-user overrides -> unnoticed API credit drain

Status Open
Maintainer reply None cached
Activity 0 comments · opened Jul 31, 2026

Summary

Over several Claude Code sessions, Claude designed and deployed an admin remote-control panel (Cloudflare Worker) for the user's internal image-studio tool that is distributed to their employees. The panel includes a global "block all" (maintenance mode) switch. The design Claude produced had critical flaws that caused real, unnoticed API spending for roughly two weeks:

  1. The global "block all" switch was soft-kill only. It was enforced client-side (the employee app's agent brain politely responds "under maintenance") while the proxy server kept forwarding paid upstream API calls (Gemini / Anthropic / others) with the company's keys.
  2. Per-employee "apply directive" silently re-enabled users. The panel's per-employee steering feature wrote targets[license_id] = {agent_directive, enabled: true}, and the server merged per-target config over the global config (Object.assign({}, global, target)). So any employee who had ever received an individual directive kept enabled: true, which silently defeated the global "block all" button.
  3. No UI indication that the effective per-user state differed from the global switch the owner had set.

Impact (user-reported)

  • The owner pressed "block all (maintenance)" and reasonably believed all employee usage was stopped.
  • 5 of 7 employees retained full access (verified today from live server config + access logs; one employee was still actively using it today).
  • The company's Google Gemini prepaid credits and Anthropic API credits were drained to $0 during the period the owner believed usage was blocked. fal.ai credits were also consumed.
  • Several hours of the owner's time today were spent discovering and diagnosing this.

The user explicitly asked that this be reported to Anthropic as model-caused damage ("the model built the switch I trusted; my money is gone"). They would like guidance on any refund/goodwill channel if one exists.

Secondary friction during incident response (today)

While fixing the incident in Claude Code (Windows 11 desktop, model claude-fable-5), the auto permission classifier repeatedly blocked legitimate remediation steps on the user's own infrastructure:

  • Blocked a POST to the user's own Cloudflare Worker admin endpoint (authenticated with the user's own local admin token) to lift the block state.
  • Blocked running an admin script that Claude had just written at the user's request (same pattern as existing scripts in the repo).

Each block forced a manual hand-off to the user mid-incident, further slowing response. Read-only calls to the same endpoint were allowed, so the blocks felt inconsistent.

What Claude should have done originally

  • Enforce a kill switch server-side (deny paid upstream calls), never only via a client-side behavioral hint.
  • Never let a convenience feature (per-user directives) silently override an explicit global kill switch; precedence should be "block wins".
  • Surface effective per-user enabled state in the admin UI.

Resolution (done today, by Claude in this session)

  • Worker fixed: global block now takes absolute precedence over per-target overrides, and the proxy now hard-rejects (503) all paid upstream routes while blocked. Deployed and verified end-to-end (block → per-user config shows disabled + paid call returns 503; unblock → restored).

Environment

  • Claude Code desktop app on Windows 11, model claude-fable-5 (panel originally built in earlier sessions, including Opus-based ones).
  • The affected system is the user's own commercial internal tool; no third-party service was harmed.

View original on GitHub ↗