Found while sweeping path predicates for #16263. Out of that card's scope (it repairs two prefix predicates in packages/runtime; this is a substring/suffix predicate in packages/core), filed unassigned.
The mechanism
isAuthGateAllowlisted (packages/core/src/security/auth-gate.ts) decides which paths are exempt from the ADR-0069 authentication-policy gate — the gate that blocks a session with an expired password or required MFA from protected resources. It matches with two unanchored tests:
if (path.includes('/auth/')) return true; // ANY position
for (const s of ALLOW_SUFFIXES) if (path.endsWith(s)) return true;
// ALLOW_SUFFIXES = ['/health', '/ready', '/discovery', '/me/apps', '/me/localization']
Neither is anchored to the start of the path, so a path that merely CONTAINS /auth/ anywhere, or ENDS WITH one of those five suffixes anywhere, is exempted.
Measured
Against the built packages/core on origin/main 7f96e1417e:
isAuthGateAllowlisted('/data/auth/123') -> true <- object named `auth`
isAuthGateAllowlisted('/meta/auth/objects') -> true <- object named `auth`
isAuthGateAllowlisted('/data/x/health') -> true <- record whose id is `health`
isAuthGateAllowlisted('/data/xyz/me/apps') -> true
isAuthGateAllowlisted('/auth/me') -> true (control: genuinely exempt)
isAuthGateAllowlisted('/data/contacts/1') -> false (control: correctly gated)
The two control rows are what prove the reading is about these paths and not about the function refusing everything or accepting everything.
HttpDispatcher.enforceAuthGate passes cleanPath to it directly, so these are reachable request paths: a tenant that declares an object named auth, or holds a record whose id is health, hands a gated user an unauthenticated-policy bypass on that object's data routes.
Why this is NOT the already-known part
The /auth/ substring width is already documented at one door, and defended there: endpoint-policy.ts deliberately does NOT pass the request path to shouldDenyAnonymous, with a comment explaining that an app-declared /api/v1/apps/NAMESPACE/auth/callback would otherwise exempt itself from its own authRequired: true. That defence covers app-declared endpoints. It does not cover the dispatcher seam, which passes the path.
ALLOW_SUFFIXES is not covered by that comment at all, and the /data/OBJECT/health row above is the shape nobody has written down.
Not fixed here
#16263 repairs the two bare startsWith PREFIX predicates (the domain registry's default and the membership skip list). This is a different predicate shape in a different package, and the repair is a different question — whether these tests should be anchored, or whether the dispatcher should stop passing a data-plane path to a control-plane allowlist at all. Riding it along would have widened a PR on a surface the card had already scoped.
Refs: #16263 (the prefix members of this sweep), #15021 (a different defect in the same function).
Generated by Claude Code
Found while sweeping path predicates for #16263. Out of that card's scope (it repairs two prefix predicates in
packages/runtime; this is a substring/suffix predicate inpackages/core), filed unassigned.The mechanism
isAuthGateAllowlisted(packages/core/src/security/auth-gate.ts) decides which paths are exempt from the ADR-0069 authentication-policy gate — the gate that blocks a session with an expired password or required MFA from protected resources. It matches with two unanchored tests:Neither is anchored to the start of the path, so a path that merely CONTAINS
/auth/anywhere, or ENDS WITH one of those five suffixes anywhere, is exempted.Measured
Against the built
packages/coreonorigin/main7f96e1417e:The two control rows are what prove the reading is about these paths and not about the function refusing everything or accepting everything.
HttpDispatcher.enforceAuthGatepassescleanPathto it directly, so these are reachable request paths: a tenant that declares an object namedauth, or holds a record whose id ishealth, hands a gated user an unauthenticated-policy bypass on that object's data routes.Why this is NOT the already-known part
The
/auth/substring width is already documented at one door, and defended there:endpoint-policy.tsdeliberately does NOT pass the request path toshouldDenyAnonymous, with a comment explaining that an app-declared/api/v1/apps/NAMESPACE/auth/callbackwould otherwise exempt itself from its ownauthRequired: true. That defence covers app-declared endpoints. It does not cover the dispatcher seam, which passes the path.ALLOW_SUFFIXESis not covered by that comment at all, and the/data/OBJECT/healthrow above is the shape nobody has written down.Not fixed here
#16263 repairs the two bare
startsWithPREFIX predicates (the domain registry's default and the membership skip list). This is a different predicate shape in a different package, and the repair is a different question — whether these tests should be anchored, or whether the dispatcher should stop passing a data-plane path to a control-plane allowlist at all. Riding it along would have widened a PR on a surface the card had already scoped.Refs: #16263 (the prefix members of this sweep), #15021 (a different defect in the same function).
Generated by Claude Code