HowAutomate
    All articles

    VITE_ Variables Are Public: Is Your Website's Admin Password Sitting in Its JavaScript?

    A common pattern in sites made with AI website builders and quick React setups: an admin page protected by a password stored in a .env file. Anyone can read it. Why, how to check your own site in two minutes, and what to do instead.

    VITE_ Variables Are Public: Is Your Website's Admin Password Sitting in Its JavaScript?

    While doing routine SEO work on a client's marketing website — a React site built with Vite, first generated by an AI website builder — we noticed it had an admin panel for editing blog posts. The panel asked for an email and password. The check happened entirely in the browser, comparing what you typed with a value stored in a .env file as VITE_ADMIN_PASSWORD. That password was readable by anyone who visited the site.

    Why .env doesn't hide anything here

    In Vite, any variable whose name starts with VITE_ is copied into the JavaScript bundle when the site is built. That's the whole point of the prefix: it marks values that are safe for the browser. The same goes for NEXT_PUBLIC_ in Next.js and REACT_APP_ in Create React App. The .env file never reaches visitors, but its VITE_ values do, inside the main .js file every browser downloads. In this case the .env file had also been committed to a public GitHub repository, so the password was public twice.

    Check your own site in two minutes

    Open your site, press F12, go to the Sources (or Debugger) tab and search across all files for words like password, admin, secret, apikey or sk-. Or download your main JavaScript file and search it. If you find a real password or a secret key, assume it's already known. Also look for login checks that only set something like isAdmin in localStorage — anyone can set that value themselves in the browser console.

    What is fine to expose

    Some keys are designed to be public: Google Analytics IDs, Firebase web config, Stripe publishable keys (pk_), map keys restricted to your domain. What must never be in the browser: admin passwords, Stripe secret keys (sk_), OpenAI or Claude API keys (anyone can run up your bill), database passwords, and service-account files.

    The fix

    Move the check to a server. The simplest version on Vercel or Netlify is a small serverless function that receives the login, compares it with a hashed password stored in the hosting platform's environment settings (without a VITE_ prefix, so it never reaches the bundle), and sets an httpOnly session cookie. The function that saves blog posts then checks that cookie. A hosted login such as Supabase Auth or Firebase Auth, with database rules that only let admins write, also works. Then change the password, remove the .env file from the repository and its history, and add .env to .gitignore. Making the repository private is good, but it doesn't help on its own — the value is still in the live JavaScript.

    Why this keeps happening

    AI site builders and starter templates make it easy to add an 'admin page' that works in the preview. It looks protected, it asks for a password, and it behaves correctly for the owner. Nothing about it looks broken until someone opens the developer tools. If your website was built quickly, by a tool or a freelancer, it's worth the two-minute check above.

    We flagged it to the client the same day. If you'd like us to check your own website's bundle and admin setup, get in touch — it's usually a short job.

    Frequently asked questions

    Are Vite environment variables secret?

    No. Any variable starting with VITE_ is copied into the JavaScript bundle at build time and can be read by every visitor. The same applies to NEXT_PUBLIC_ and REACT_APP_ variables.

    How do I check if my website exposes a password or API key?

    Open the site, press F12, and search all source files for words like password, admin, secret, apikey or sk-. Anything real you find should be treated as already leaked and changed.

    How should an admin login work on a static or Vite website?

    Check the password on a server — for example a serverless function comparing against a hashed password in the hosting platform's private settings and setting an httpOnly cookie — or use a hosted login like Supabase Auth or Firebase Auth with database rules.

    Does making my GitHub repository private fix it?

    Only partly. It stops people reading the file in the repository, but a VITE_ value is still inside the live website's JavaScript. Move the secret to the server and change it.

    Get weekly automation tipsReal scripts, workflows and AI tips, straight to your inbox.

    Keep reading

    Want us to set this up for you?

    Chat with us