npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vite-plugin-safe-env

v1.1.0

Published

A Vite plugin that prevents server-only environment variables from leaking into client-side bundles.

Downloads

165

Readme

Vite ensures only VITE_-prefixed variables are exposed through import.meta.env, but offers no such protection for process.env (exposed by define: { 'process.env': loadEnv(...) }). A server-side module accidentally imported into the client entry tree can silently inline credentials like DATABASE_URL or JWT_SECRET into the production bundle, readable by anyone who downloads the JavaScript file.

vite-plugin-safe-env catches this class of bug through two detection phases:

Phase 1 (Static analysis): Scans every source module for process.env.X and import.meta.env.X accesses, walks the module graph to find which of them are reachable from client entry points, and reports violations with the exact file, line, and import chain.

Phase 2 (Bundle scan): After the bundle is produced, scans every output chunk for the literal string values of known server-only variables. This is the ground-truth gate. If a secret's value appears in the output, the build fails.

Why this matters

The risk is documented and has affected real production systems.

Sprocket Security (2024): AWS credentials and CircleCI API keys were found as plain strings in a production Vite bundle. A server-side module had been accidentally imported from the client entry tree. The exposed keys granted full access to the CI/CD pipeline, all stored secrets, and every connected repository.

Vite issue #17710: Confirmed bug where referencing a non-existent env variable causes Vite to inline the entire process.env object into the client bundle, exposing every secret available in the build environment.

Installation

npm install -D vite-plugin-safe-env
pnpm add -D vite-plugin-safe-env
yarn add -D vite-plugin-safe-env

Usage

Zero configuration required.

// vite.config.ts
import { defineConfig } from 'vite'
import safeEnv from 'vite-plugin-safe-env'

export default defineConfig({
  plugins: [safeEnv()],
})

How it works

What gets flagged

Any environment variable accessed without a client-exposed prefix (your envPrefix configuration, or VITE_ by default) that is reachable from a client entry point:

// leaking-usage.ts (imported from a client entry)
export const dbUrl = process.env.DATABASE_URL // flagged
export const dbUrl2 = import.meta.env.DATABASE_URL // also flagged
export const apiUrl = import.meta.env.VITE_API_URL // safe, has VITE_ prefix

import.meta.env.DATABASE_URL is flagged even though Vite resolves it to undefined: the access is a silent bug, missing at runtime with no build-time error. To use a variable on the client, give it a prefix Vite exposes (your envPrefix, VITE_ by default) or add it to allowClientAccess.

Error output

[vite-plugin-safe-env] Server-only environment variable may leak to client bundle

  Variable    DATABASE_URL
  File        src/utils/db.ts:3

  Reachable via
              src/main.tsx
              src/components/UserCard.tsx
              src/utils/db.ts

  Risk
  The value of DATABASE_URL will be visible in your production
  JavaScript bundle to anyone who opens browser DevTools.

  Fix
  DATABASE_URL appears to be a credential. Exposing it in the client bundle
  is a security vulnerability. Move all access into a server-only module that
  is never imported from a client entry point.

In development mode, violations appear as a browser overlay using the same style as Vite's built-in TypeScript error overlay.

Known limitation

Phase 1 only detects named accesses like process.env.DATABASE_URL. Computed names like process.env[key] are invisible to static analysis. Phase 2 compensates by scanning the compiled bundle for the actual string values of server variables.

Configuration

All options are optional. The plugin is non-intrusive by default.

safeEnv({
  // Variables explicitly permitted on the client side, even without the VITE_ prefix.
  // Default: []
  allowClientAccess: ['NODE_ENV', 'BUILD_SHA'],

  // When to abort the build on a detected leak.
  // 'production' aborts only when NODE_ENV is production (default)
  // 'always'     aborts on every build
  // 'never'      reports violations but never aborts
  blockOn: 'production',

  // Glob patterns for source files to scan.
  // Default: ['**/*.{ts,tsx,js,jsx,vue,svelte}']
  include: ['src/**/*.ts'],

  // Glob patterns for source files to skip. Takes precedence over include.
  // Default: ['node_modules/**', 'dist/**']
  exclude: ['src/generated/**'],

  // Show the browser overlay in development mode.
  // Default: true
  overlay: true,
})

Examples

Allow specific non-prefixed variables

Some projects use variables like NODE_ENV or CI on the client intentionally:

safeEnv({
  allowClientAccess: ['NODE_ENV', 'CI', 'BUILD_TIMESTAMP'],
})

Strict mode

Fails the build regardless of environment. Useful in CI pipelines that run against staging:

safeEnv({ blockOn: 'always' })

Warning-only mode for gradual adoption

Reports all violations to the terminal without blocking the build. Useful when adding the plugin to an existing codebase with many violations:

safeEnv({ blockOn: 'never' })

License

MIT License © 2026-present Cong Nguyen