fix(start-env): reject public-prefixed keys in the server schema - #302
Conversation
…akes every VITE_-prefixed var into the browser's import.meta.env regardless of schema side, so a server-declared VITE_* secret leaked silently through Vite's own channel (the leak scan only watches the virtual server module's values); the prefix rule is now enforced both ways, with a fixture and guard assertion in the start-env suite Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 3cbd3f9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
ryansolid
left a comment
There was a problem hiding this comment.
Confirmed the gap: on next.24, server: { VITE_API_SECRET: ... } builds silently, and in dev the value is served straight to the browser the moment any client module references import.meta.env.VITE_API_SECRET (verified against a live dev server). Fail-fast at config time is the right call, the message is actionable, and the fixture + guard assertion follow the suite's conventions — full suite passes 45/45 here, and I confirmed the new assertion fails without the src fix. One note: the changeset says the leak scan "only watches the virtual server module's values" and can't catch this — the scan actually does catch the build-referenced case (it matches server values as literals in client chunks); the uncovered surface is dev (no scan) plus short/colliding values. No change needed from you — I'm tightening the changeset wording at merge on our side so the changelog doesn't undersell the existing scan. The guard itself needs no changes.
Problem
start.envenforces the public-prefix rule one-way only:clientkeys must carry theVITE_prefix (or whateverenvPrefixselects), butserverkeys are never checked for having it. Vite bakes every prefixed variable into the browser'simport.meta.envregardless of which side of the schema declares it, so this config:ships the secret to every client through Vite's own channel — silently. The plugin's client-chunk leak scan can't catch it because it only watches the virtual server module's values, not
import.meta.env. In dev the full value is served to the browser; in build any client reference toimport.meta.env.VITE_API_SECRETinlines it.Preventing exactly this class of leak is the core promise of
start.env, so the gap undermines the feature.Fix
assertSchemaShapenow rejectsserverkeys that carry any configured public prefix, failing fast at config time — mirroring the existing client-side guard — with a message explaining why (servercannot keep a prefixed var secret) and what to do (rename it without the prefix in the schema and the environment, or move it toclientif it's public).Tests
Added
examples/start-env/env.serverprefix.ts(fixture, following the existingenv.badprefix.tspattern) and a guard assertion in the start-env suite. Full suite passes locally: 45/45 assertions.🤖 Generated with Claude Code