~/teardowns/TD-047.md
←Back to teardowns
# TD-047MediumRuntimecase study

The Claim That Rewrote Itself on Every Sign-In

undefined !== false — how a missing claim turned every non-staff login into a writes storm

Published Nov 5, 2026

Executive Summary

A profile bootstrap compared a token claim against a computed staff flag with strict inequality. A non-staff account carries no such claim at all, so `undefined !== false` was always true: every sign-in rewrote custom claims, forced a token refresh, and logged a false security event. The fix treats an absent claim as 'not staff' explicitly and pins all four states with unit tests.

The Prompt

“Add a bootstrapProfile callable that keeps the user's staff flag in sync with their custom claims on sign-in.”

The Flaw

The sync compared the raw token claim against the computed staff flag with strict inequality. But a non-staff account has no `staff` claim at all — the token simply doesn't carry it — so the left side is `undefined`, not `false`. `undefined !== false` is always `true`, so every non-staff sign-in 'detected' a change that never happened: it rewrote the custom claims, forced a client token refresh, and wrote a `staff_claim_cleared` security event. The code treated 'no claim' and 'claim is false' as the same thing; JavaScript doesn't.

Risk & Impact

[Correctness] Every non-staff sign-in rewrote the custom claims, forced a token refresh, and logged a false security event — 17 events for 3 users in 10 minutes.

Cost: False security events flood the audit log and would eventually drown out a real `staff_claim_cleared` (an actual privilege removal).

Code Comparison

❌ Vulnerable (AI generated)

functions/src/index.tsts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// bootstrapProfile — runs on every sign-in
const existingClaims = (auth.token ?? {}) as Record<string, unknown>;
const isStaff = isStaffCaller(auth);
// A non-staff account has no `staff` claim at all, so this is:
// undefined !== false → true — on every single sign-in
if (existingClaims.staff !== isStaff) {
await getAuth().setCustomUserClaims(uid, {
...(existingClaims.creator === true ? { creator: true } : {}),
...(existingClaims.venueAdmin === true ? { venueAdmin: true } : {}),
...(isStaff ? { staff: true } : {}),
});
}
// ...and in the response payload:
claimsUpdated: existingClaims.staff !== isStaff,

The Fix

Treat an absent claim as 'not staff' explicitly via a helper, and pin all four states (absent / undefined / true / false) with unit tests.

Prevention

  • [manual] At any auth or trust boundary, decide explicitly what an absent value means — never rely on `undefined !== false` to work out.
  • [ci] Require unit tests that cover absent and undefined claim states for any code that writes custom claims or security events.

Why This Happened

Root cause: the prompt omitted Rule 4 and Rule 11 — the guardrails that would have caught this. See the full guide →

Sources

Is your codebase vulnerable to this?

Run Diagnostic on My Project →