[Bug] Claude Code incorrectly flags legitimate security audit workflow as problematic

Open 💬 0 comments Opened Jun 10, 2026 by anassnammal-inelm

Bug Description
why these prompts get flaged by fable 5:
Prompt 1:

now i need you to audit and review the auth system in ./api

● Auth audit of api/ — I'll map the auth surface first, then review each piece in depth.

Searched for 1 pattern, read 4 files, listed 1 directory (ctrl+o to expand)

● 3 agents finished (ctrl+o to expand)
├ Review auth domain core · 15 tool uses · 44.4k tokens
│ ⎿ Done
├ Review token/session lifecycle · 33 tool uses · 67.0k tokens
│ ⎿ Done
└ Review auth perimeter/routes · 31 tool uses · 44.9k tokens
⎿ Done

● Excellent raw material. Before I report, let me verify the five most serious claims directly — agents can be wrong:

● Bash(sed -n '60,110p' src/domain/auth/services/auth.ts; echo '====verify-email token gen===='; sed -n '405,435p' src/domain/auth/services/auth.ts)
⎿ },
},
};
… +80 lines (ctrl+o to expand)

● Bash(sed -n '165,190p' src/utils/helpers.ts; echo '====queuedash===='; sed -n '38,60p' src/index.ts; echo '====gracht webhook handler===='; grep -n -A12 'handleGrach…)
⎿ });
}
return items;
… +61 lines (ctrl+o to expand)

● All top findings verified first-hand in the source. Here's the consolidated audit.

Auth System Audit — api/

Overall: the foundation is genuinely good — pinned HS256, separate access/refresh secrets, refresh rotation with reuse blacklisting, jti-based revocation, bcrypt, CSPRNG
codes, hashed API keys, correct route-mounting order. But there are two critical design flaws and a cluster of high-severity gaps that undermine it.

Critical

  1. Email-verification tokens work as full access tokens — auth.ts:98-106, 408-432

verifyAccessToken() only checks the signature; it never checks the token's type claim. The partner_verify_email and agent_password_setup tokens are signed with the same
JWT_SECRET and carry userId + jti — everything ConsoleAuthMiddleware requires. So a verification link from an email (shared inbox, forwarded mail, proxy logs) can be pasted
into Authorization: [REDACTED] and grants a full, non-read-only console session for 10 minutes — even for a PENDING, unverified account, because of finding 3. The Redis
single-use whitelist doesn't help; the middleware never consults it.
Fix: require an explicit token type on access tokens (or reject any token carrying a type claim) in verifyAccessToken.

  1. Hardcoded JWT secret fallbacks activate silently in production — auth.ts:68-71 (repeated at :253, :409, :514, :590, :627)

getEnv("JWT_SECRET") || "your-secret-key-change-in-production". I verified getEnv (envconfig.ts:93-100) only throws on missing vars in non-production — in prod it returns
"", so the || picks the committed fallback. One bad deploy with the env var unset and anyone can forge tokens for any user. Same pattern on the refresh secret.
Fix: delete the fallbacks; fail at startup in all environments.

  1. Suspended/disabled users are never rejected — helpers.ts:172-187

isValidUser() — the single authority for both ConsoleAuthMiddleware and ApiAuthMiddleware — only checks the user exists. Neither it nor login() checks user.status or
company status. An offboarded or fraud-suspended partner keeps logging in, keeps using 7-day JWTs, and their API keys keep working. There is currently no way to lock anyone
out short of deleting the row.

  1. Hardcoded QueueDash credentials in source — index.ts:42-43

USERNAME = "imad"; PASSWORD = "[REDACTED]" guards /queuedash, which can view, retry, delete, and promote every BullMQ job — order dispatch, wallet adjustments, invoices.

High

  1. Gracht webhook is unauthenticated — webhooks/Routes.ts:10, gracht.service.ts:336-344. No secret, no signature; the reference key is the predictable order_<orderId>.

Mitigating nuance (verified): the handler re-polls Gracht's real order-details, so an attacker can't inject fake vouchers — but they can drive premature pipeline
transitions for any order at will. Volga at least checks a body secret (with non-constant-time !==).

  1. Spoofable client IP — requestMetadata.ts:18-22. getClientIp trusts the cf-connecting-ip header unconditionally, without verifying the connection comes from Cloudflare.

That header is the enforcement input for the API-key IP whitelist (ApiAuthMiddleware.ts:34-45) and the rate-limit bypass list. If the origin is reachable around Cloudflare,
a lea…
Note: Content was truncated.

View original on GitHub ↗