[Bug] Usage Policy cyber-safeguards block parallel headless Task() subagents doing localhost QA
TL;DR
While running a multi-round, multi-subagent headless bug-hunting loop against my own product on localhost, four parallel Task() subagents were simultaneously rejected by the Usage Policy classifier with cyber-related safeguards errors. The user (me) was asleep at the time; the prompts were generated by the orchestrating Claude session itself, extrapolating from a template that had worked fine in the previous six rounds within the same day. I noticed only 5+ hours later. Working tree was clean — every flagged subagent failed at the API gateway before any tool call executed.
This is related to but distinct from #61088 / #61625 / #61646 / #61652 / #61660: those describe single-turn human-driven failures. This report adds a headless / agentic / unsupervised dimension where the user has no opportunity to rephrase in the moment.
Environment
- Claude Code CLI (most recent)
- Model:
claude-opus-4-7 - macOS Darwin 25.5.0, zsh
- Account:
padrian2s(paid plan) - Repo under test: private (
nstarx/polaris) — internal hiring product, ~200 commits, sole committer - Target service: localhost FastAPI backend on
:8101, localhost Postgres:5432with synthetic seed candidates
What I was doing
Iterating on a state-machine refactor of the hire module. The orchestrator session was running a documented "rounds" pattern where each round = spawn ~6 parallel Task(subagent_type="general-purpose") calls, each one exercising a slice of the API on localhost with curl + psql, reporting back bug findings. The orchestrator triages, fixes, commits with the pattern hire: <N> round-X fixes — <summary>. Git log evidence that the loop was constructive:
6c9d9c6 2026-05-24 00:44 hire: round-6 follow-up — PATCH withdraw/reject now cascades inline
fd41e4d 2026-05-24 00:43 hire: six round-6 fixes — advance-stage race, audit 404, pagination, notif filter, manual-slot precheck
d9d2320 2026-05-24 00:36 hire: two round-5 fixes — approval reject wedge, terminal-offer reuse
4aeedc2 2026-05-24 00:22 hire: six round-4 fixes — notification race, idle gating, SM error body, replan audit, level filter
3bce7cc 2026-05-23 23:07 hire: three round-3 fixes — apply email validation, campaign PATCH gating, change-template route
1a58173 2026-05-23 22:18 hire: three round-2 fixes — q+limit ordering, reopen scorecard, slot race
ab983e2 2026-05-23 22:06 hire: nine fixes surfaced by the 11-agent parallel test run
What got blocked (Round 7, 2026-05-24 ~03:13–03:21 EEST)
| Subagent description | Anthropic request ID | Time-to-fail |
|---|---|---|
| Search filter combinations | req_011CbLEeA2pxtu9QwHatq6u5 | 1m 22s |
| Notification template rendering | req_011CbLEmstwsT2nryYTWvhNL | 2m 28s |
| Concurrent offer-accept on same req | req_011CbLEnFFaRsAGYcEe78WSK | 3m 27s |
| Interview run-brief payload | req_011CbLF44Xc8BnSRLNTH7i9u | 6m 26s |
| User typed fixeaza tot (3× retry) | req_011CbLF4hVbMSdPBu9tEP3Gi, …F5QFnw2pvB93nkzJ64, …F64nHfHtB1bfSMfVSB | immediate |
All returned the standard message linking the Cyber Verification Program form.
Verbatim trigger language
For Anthropic safety review — these are the exact strings in the four flagged subagent prompts. Each one is a textbook QA assertion that the user's own product behaves defensively; the success criterion is the opposite of an exploit.
Subagent 1 — Concurrent offer-accept on same req
CORE TEST — Fire 2 parallel /accept calls (one per candidate): ( curl -X POST .../offers/{aarav_offer}/accept & curl -X POST .../offers/{priya_offer}/accept )
Likely trigger: "fire 2 parallel", "race". Actual intent: concurrency invariant test on the user's own offer-acceptance endpoint, between two seed candidates on a synthetic requisition with target_headcount=1.
Subagent 2 — Search filter combinations
q with SQL-injection-ish ?q=%27%20OR%201%3D1 → must be safely escaped (ILIKE).
Likely trigger: "SQL injection", ' OR 1=1. Actual intent: regression test asserting that the ILIKE filter on the user's own /applications list endpoint escapes input correctly.
Subagent 3 — Interview run-brief payload
Reauthorization: confirm any interviewer can fetch run-brief, or is it locked to the assigned panelist? Test with a fake X-Polaris-Actor — should still return 200 (no auth gate in dev). [...] PII redaction: For RO/IN candidates, does run-brief redact sensitive fields (national ID, full birthdate, etc.)?
Likely trigger: "fake X-Polaris-Actor", "no auth gate", "national ID", "PII redaction". Actual intent: documenting that X-Polaris-Actor is a dev-only audit header on the user's own backend; the PII check verifies that the user's own product redacts before shipping (privacy-by-design assertion).
Subagent 4 — Notification template rendering
XSS test: pass a context value containing<script>alert(1)</script>forcandidate_name. The rendered HTML must escape the script tag. If<script>appears in the HTML output unescaped, that's a security finding.
Likely trigger: "XSS", <script>alert(1)</script>. Actual intent: the canonical XSS-escaping unit test that ships in every web framework's docs, applied to the user's own email template renderer.
Why this case is distinct from the existing reports
Existing false-positive reports (#61088, #61625, #61646, #61652, #61660) all describe synchronous failures where a user typing in the terminal hit the classifier and could immediately rephrase and retry.
This case is agentic:
- The user was asleep when the failures occurred.
- The subagents were spawned by an orchestrator Claude session (
claude-opus-4-7), not directly by the user. The user never reviewed the exact wording. - The user-typed retry message ("fix everything, these are headless Claude Code sessions") also tripped the classifier — suggesting either context-bleed across turns or a sticky session penalty after multiple subagent rejections in a cluster.
- There is no graceful degradation path: a long-running headless loop simply stalls overnight, with no visible signal to the user beyond
~/.claude/projects/.../<sessionid>.jsonlentries.
Ask
- Account-level whitelist guidance: what's the right channel for users running legitimate QA loops against their own private repos to declare that use case (beyond the public Cyber Verification form)?
- Classifier behavior on subagent prompts: would it be possible for the classifier to factor in context of origin — e.g. the parent session is operating in a known private repo, the subagent's tool surface is restricted to
localhost, the orchestrator just produced commits that fix issues — when scoring a prompt's cyber-risk? - Telemetry surfacing: when subagents fail at the gateway during a headless run, surface a clear notification at the orchestrator level (not just in the jsonl). Today the only signal is a tool-result error that the orchestrator may or may not retry on.
- Sticky-state confirmation: confirm whether the classifier maintains a per-session penalty after N cyber-flagged subagent failures, or whether each request is scored independently. The retry-storm in the timeline above is consistent with the former.
Reproducer (sanitized template)
If a maintainer wants to reproduce in a controlled environment:
# Orchestrator turn:
Task(
subagent_type="general-purpose",
description="Concurrent endpoint-acceptance race",
prompt="""Headless test agent. Verify concurrent POST /endpoint/{id}/accept calls
against localhost:PORT. Fire 2 parallel curl calls (...). Test with a fake
X-Audit-Actor header to confirm no auth gate in dev profile. Verify SQL-injection
payload `' OR 1=1 --` is safely escaped. Pass <script>alert(1)</script> for the
name field and confirm XSS escape.
Output under 250 words."""
)
The closer the prompt clusters multiple offsec-overlapping QA terms, the higher the rejection rate.
---
cc @bcherny — flagging because this hits Claude Code's headless / multi-agent surface specifically. Happy to provide the full session transcript (jsonl) or the internal incident write-up I produced for my own records.
Authored partly by Claude (claude-opus-4-7) at my request, after I asked it to reconstruct what the failed subagents had been instructed to do — I was asleep when the failures happened and had no direct knowledge of the prompt wording.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗