Summary
The Nuxt security proxy prefers raw string sources over the coerced validation target on both the client and server branches, so coercion (ADR 0002) is silently bypassed: a key typed as number returns a raw string at runtime.
Details
In packages/nuxt/src/create-env.ts (~lines 327–372), the proxy getter resolves schema keys in this order:
- Client branch:
runtimeEnv → useRuntimeConfig().public (raw strings) → __NUXT__.config.public (raw strings) → coerced target.
- Server branch:
runtimeEnv → runtimeConfig[prop] / runtimeConfig.public[prop] (raw strings) → raw process.env[prop] → coerced target.
Severity on the server: prop in process.env is near-always true for schema keys (they were just validated from it), so the coerced target is effectively unreachable in the common path unless runtimeEnv explicitly owns the key. Server-side coercion is broken by default, not just in edge cases.
Fix direction
Coerce values before they enter the runtime payload rather than shipping a validator to the client. Implementation note: Nitro applies NUXT_PUBLIC_* runtime overrides as strings at boot, so the fix needs a boot-time coercion pass (e.g. a Nitro plugin), not just build-time injection.
Acceptance criteria
Landing
Lands on dev first (bug fix affecting current users), then forward-port to v1 per the dual-tracking flow.
Part of #1105 (ADR 0015, #1326) — the aligned model's honesty claim is only as good as its weakest integration.
Summary
The Nuxt security proxy prefers raw string sources over the coerced validation target on both the client and server branches, so coercion (ADR 0002) is silently bypassed: a key typed as
numberreturns a rawstringat runtime.Details
In
packages/nuxt/src/create-env.ts(~lines 327–372), the proxy getter resolves schema keys in this order:runtimeEnv→useRuntimeConfig().public(raw strings) →__NUXT__.config.public(raw strings) → coerced target.runtimeEnv→runtimeConfig[prop]/runtimeConfig.public[prop](raw strings) → rawprocess.env[prop]→ coerced target.Severity on the server:
prop in process.envis near-always true for schema keys (they were just validated from it), so the coerced target is effectively unreachable in the common path unlessruntimeEnvexplicitly owns the key. Server-side coercion is broken by default, not just in edge cases.Fix direction
Coerce values before they enter the runtime payload rather than shipping a validator to the client. Implementation note: Nitro applies
NUXT_PUBLIC_*runtime overrides as strings at boot, so the fix needs a boot-time coercion pass (e.g. a Nitro plugin), not just build-time injection.Acceptance criteria
"string.numeric"with coerce) returns anumberon both server and client, including when overridden viaNUXT_PUBLIC_*at boot.process.envfallback path.Landing
Lands on
devfirst (bug fix affecting current users), then forward-port tov1per the dual-tracking flow.Part of #1105 (ADR 0015, #1326) — the aligned model's honesty claim is only as good as its weakest integration.