You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Dev-only gates spelled NODE_ENV !== 'production' still open in a real production deployment that never sets NODE_ENV (os serve does not force it, os start does) #11113
Filed as the declared residual of #10366, whose maintainer ruling (2026-08-22) is being implemented as literally ruled. Filing rather than silently tightening, per the disposition precedent in #11035. Unassigned and unlabelled — this is for triage, not a grade.
The residual
#10366 gates the localhost trusted-origin substitution in packages/plugins/plugin-auth/src/auth-manager.ts on the ruling's literal
predicate:
process.env.NODE_ENV!=='production'
When NODE_ENV is unset, undefined !== 'production' is true. So a real
production deployment that never sets NODE_ENV is still treated as
non-production and still receives the development convenience.
The ruling's literal text governs, and tightening it to === 'development'
would be a stricter boundary than ruled — it would break test and
unset-NODE_ENV development flows. So #10366 implements it as ruled and
records the gap here instead.
Measured — the gap is narrower than it first reads, and it is not zero
Re-derived on origin/main @ 24043c290:
os start forces it.packages/cli/src/commands/start.ts:347 — if (!localEnv.NODE_ENV) localEnv.NODE_ENV = 'production';, with the comment "NODE_ENV is only forced to production when the user has not set it."
A deployment booted through os start therefore lands on production without
the operator doing anything. packages/cli/src/commands/doctor.ts:213 already
advertises this as settled ("what os start already forces").
So the residual is real but confined to the os serve shape.
Why this is worth its own card rather than a wider predicate
The pattern is not local to one call site. auth-manager.ts alone carries
several spellings of the environment test — !== 'production', === 'production', === 'development' — and the !== 'production' ones all
share this open end. Whatever is decided here should be decided once for the
family, not per gate:
Make os serve default NODE_ENV to production the way os start
already does — one line, moves every !== 'production' gate at once, and
makes the two boot commands agree.
Introduce a single reusable predicate that treats unset as production
for security-relevant gates specifically, leaving DX gates on the current
spelling.
Accept it and document that NODE_ENV must be set explicitly for os serve
production deployments.
⛔ Not claimed. I did not assess exploitability, and I did not survey which
other !== 'production' gates in the tree would change behaviour under options
1 or 2 — that survey is the bulk of the work and belongs to whoever takes this.
The relevant property, stated without recipe: a gate whose intent is "not in
production" currently fails open when the environment is undeclared.
Filed as the declared residual of #10366, whose maintainer ruling (2026-08-22) is being implemented as literally ruled. Filing rather than silently tightening, per the disposition precedent in #11035. Unassigned and unlabelled — this is for triage, not a grade.
The residual
#10366 gates the localhost trusted-origin substitution in
packages/plugins/plugin-auth/src/auth-manager.tson the ruling's literalpredicate:
When
NODE_ENVis unset,undefined !== 'production'istrue. So a realproduction deployment that never sets
NODE_ENVis still treated asnon-production and still receives the development convenience.
The ruling's literal text governs, and tightening it to
=== 'development'would be a stricter boundary than ruled — it would break
testandunset-
NODE_ENVdevelopment flows. So #10366 implements it as ruled andrecords the gap here instead.
Measured — the gap is narrower than it first reads, and it is not zero
Re-derived on
origin/main@24043c290:os startforces it.packages/cli/src/commands/start.ts:347—if (!localEnv.NODE_ENV) localEnv.NODE_ENV = 'production';, with the comment"NODE_ENV is only forced to production when the user has not set it."
A deployment booted through
os starttherefore lands onproductionwithoutthe operator doing anything.
packages/cli/src/commands/doctor.ts:213alreadyadvertises this as settled ("what
os startalready forces").os servedoes not. No equivalent assignment exists inpackages/cli/src/commands/serve.ts.os serveis also the only productionAuthManagerconstruction site in this repo (enumerated on AuthManager trusts localhost wildcards for CSRF in production whenever trustedOrigins arrives empty — measured #10366). Adeployment run through
os servewithNODE_ENVunset is production in everysense except the one the predicate can see.
So the residual is real but confined to the
os serveshape.Why this is worth its own card rather than a wider predicate
The pattern is not local to one call site.
auth-manager.tsalone carriesseveral spellings of the environment test —
!== 'production',=== 'production',=== 'development'— and the!== 'production'ones allshare this open end. Whatever is decided here should be decided once for the
family, not per gate:
os servedefaultNODE_ENVtoproductionthe wayos startalready does — one line, moves every
!== 'production'gate at once, andmakes the two boot commands agree.
for security-relevant gates specifically, leaving DX gates on the current
spelling.
NODE_ENVmust be set explicitly foros serveproduction deployments.
⛔ Not claimed. I did not assess exploitability, and I did not survey which
other
!== 'production'gates in the tree would change behaviour under options1 or 2 — that survey is the bulk of the work and belongs to whoever takes this.
The relevant property, stated without recipe: a gate whose intent is "not in
production" currently fails open when the environment is undeclared.
Related
OS_AUTH_URLmechanism; its''-coalescing question isparked and stays parked.
Recorded from the
os-devseat implementing #10366; every line number above wasre-derived in a worktree off
24043c290.Generated by Claude Code