Skip to content

Environment And Bindings

R-ENV-1 - Client environment variables are public

Severity. blocker when a secret-like value is exposed to the client bundle; otherwise medium when the split between public config and server config is undocumented.

Rule. Frontend environment variables may contain public configuration only. Secrets live in Cloudflare bindings or deployment secrets.

Why. Vite-style client env values are bundled into browser assets.

vcqa. Flag secret-like VITE_* variables and frontend imports from server-only config. Concretely: any VITE_-prefixed name matching SECRET|TOKEN|PRIVATE|PASSWORD|_KEY that is not explicitly marked publishable; any browser module importing the Functions Env type or a server config module; any .env* with real values that is not gitignored.

Evidence.

  • Source/config: .env* files, vite.config.*, browser env access sites, the deploy workflow's build-time environment block.
  • CI/artifacts: build log or secret scan over the published output directory.
  • Negative evidence: no production secret string appears in built assets.
  • Exception: not available for secret values. A publishable key may carry an acceptedException naming why it is safe to publish.

References.

R-BIND-1 - Bindings are environment-scoped

Severity. blocker when preview and production resolve to the same underlying resource ID or the same secret value; otherwise high when the separation exists but the deploy path does not select an environment explicitly.

Rule. Preview, staging, and production bindings are named and reviewed separately, and the deploy path selects the intended environment explicitly.

Why. Accidental reuse of production bindings in previews is a common fullstack Pages failure mode.

vcqa. Inspect Wrangler config and deployment workflows for environment-specific binding names. Compare the concrete identifiers, not just the binding names:

  • [[d1_databases]] database_name and database_id;
  • [[kv_namespaces]] id and preview_id;
  • [[r2_buckets]] bucket_name and preview_bucket_name;
  • [[queues.producers]] queue names, [[hyperdrive]] ids, and service bindings;
  • [env.preview] / [env.production] (or the Pages preview/production variable and secret sets) carrying different values for each of the above.

Flag any resource ID that appears in more than one environment, any environment block that inherits a production ID by omission, and any deploy command that does not select the environment or branch it intends.

Evidence.

  • Source/config: wrangler.toml/wrangler.jsonc environment blocks, or the documented Pages project preview/production variable and secret sets.
  • CI/artifacts: deploy log showing the selected environment or branch, and the binding set applied.
  • Runtime/deploy: a preview deployment reading a preview resource, demonstrated by a smoke request whose data is preview data.
  • Exception: acceptedException for a deliberately shared non-production sandbox, naming owner, scope, environments, compensating controls, evidence, and expiry/review date. Sharing a production resource with preview is not an acceptable exception.

References.

R-BIND-2 - Binding types are documented at the Function boundary

Severity. medium, escalating to high when an undeclared binding is used by a handler that performs writes or authorization.

Rule. Function context bindings must have TypeScript definitions or documented runtime names, and every binding a handler reads from env must appear in that declaration.

Why. Unclear binding names cause runtime-only failures and make scanner findings less actionable.

Scoring. A pass requires a single declared source of binding names — an Env interface, a worker-configuration.d.ts generated by wrangler types, or an equivalent documented list — and no env.X access whose X is missing from it.

vcqa. Check for environment binding types, generated Cloudflare types, or equivalent interfaces; diff the declared binding names against env. property accesses across functions/** and against the binding blocks in Wrangler config.

Evidence.

  • Source/config: the Env interface or generated types, Wrangler binding blocks, env. access sites.
  • CI/artifacts: tsc/wrangler types step in the pipeline and its freshness relative to the config.
  • Exception: acceptedException naming the undeclared binding, why it is dynamic, and the compensating runtime check.

References.

R-ENV-2 - Local and preview configuration are explicit

Severity. medium, escalating to high when the undocumented local path is the one a contributor would reach for first and it silently binds production resources.

Rule. Local development and preview deployments must document how bindings are mocked, seeded, or replaced, and the documented commands must exist in the repo.

Why. A fullstack Pages app often behaves differently locally unless bindings are accounted for.

vcqa. Check docs, scripts, or Wrangler config for local binding strategy. Look for a local dev command (wrangler pages dev <dir> or the package script that wraps it), local binding flags or [env.local]-style configuration, .dev.vars handling and gitignore status, and a seed/migration script for local data.

Evidence.

  • Source/config: package.json scripts, .dev.vars.example, Wrangler local config, seed or migration scripts.
  • CI/artifacts: any workflow that runs the same local preview path.
  • Runtime/deploy: the documented command starts a preview that serves both the assets and the Functions.
  • Exception: acceptedException when local development is intentionally unsupported, naming the owner and the supported alternative.

References.