This question gets asked by developers who just generated a feature with Windsurf's Cascade agent, glanced at the diff, and noticed their .env file mentioned somewhere along the way. The honest answer separates three different things that often get bundled together under the word 'leak', and only one of them is something the build tool actually does.
Short answer
Cascade does not automatically write the contents of your .env file into the browser bundle. The build tool decides what reaches the client: Vite inlines variables prefixed with VITE_, and Next.js inlines anything prefixed with NEXT_PUBLIC_. The risk that does involve Cascade is a separate prompt-injection class disclosed by Embrace The Red in August 2025, where the agent can be tricked into reading .env and shipping it to an attacker server through auto-approved tools.
What you should know
- The bundler, not the IDE, decides what ends up in browser JavaScript. Cascade writes the source code;
vite buildornext buildperforms the inlining. - Build-time inlining is irreversible. Once
process.env.NEXT_PUBLIC_Xis in your bundle, every browser that loads the page sees that string. - Cascade reads files it can see. If
.envsits in the workspace and is not blocked, the agent has read access by design. - Prompt injection in source files or READMEs can hijack Cascade. A May 2025 disclosure showed unapproved tool calls can exfiltrate
.envto attacker servers. .gitignoredoes not protect a file from Cascade. Git ignores it for commits; Windsurf indexes it for the agent unless you exclude it through.codeiumignore.
What does "leak to the client" actually mean here?
The word 'leak' covers three different surfaces, and conflating them is the most common source of confusion in this question.
The first surface is the browser bundle: the JavaScript that ships to end users. A secret reaches it only if the build tool inlines it, which requires both the right naming prefix and a reference to that name inside client-side code.
The second surface is the editor's network. Cascade sends portions of your project to Codeium's inference servers to generate completions. The company does not promise that no .env content ever touches that inference path. Treat this as a trusted-vendor relationship, not a zero-knowledge one.
The third surface is third-party exfiltration. A prompt-injection payload hidden in a dependency, README, or open file can instruct Cascade to call a tool that reaches an attacker server. The data goes through Cascade, not through your build, and the exfiltration is invisible in the diff you review.
These three surfaces have different fixes. Mixing them produces panic in one direction or false comfort in the other.
Does Cascade write your .env values into the JavaScript bundle?
No. Cascade writes TypeScript or JavaScript source code. The bundler reads that source and decides what gets inlined.
For Vite projects, the official environment variable documentation is explicit: variables prefixed with VITE_ are exposed in client-side source code after Vite bundling. Anything without the prefix stays in process.env on the Node.js side and is stripped from the browser output. The same page adds a direct warning that VITE_* variables should not contain sensitive information such as API keys, because their values are baked into source code at build time.
For Next.js, the rule has the same shape with a different prefix. The Next.js environment variables guide states that to expose an environment variable to the browser, it must be prefixed with NEXT_PUBLIC_, and these public environment variables are inlined into the JavaScript bundle during next build. Inlining means literal substitution: process.env.NEXT_PUBLIC_ANALYTICS_ID becomes the string "abcdefghijk" in every chunk that referenced it.
What Cascade can do, and sometimes does, is suggest the wrong prefix. If a generated component reads process.env.NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY, the build will obligingly bake the service role key into the client bundle, with no warning. The leak then comes from the prefix choice in the generated code, not from .env itself.
Has Cascade been caught reading .env files for someone else?
Yes, in a documented research disclosure. Johann Rehberger of Embrace The Red published a chain in which Cascade's read_url_content tool, which does not require human approval, was used as both a data fetch and a data exfiltration channel. An indirect prompt injection embedded in a project file directed Cascade to read .env and pass its contents as part of an outbound HTTP request to an attacker-controlled server.
The timeline matters. The disclosure was sent to Windsurf on May 30, 2025; public disclosure followed on August 21, 2025, after the researcher reported receiving no fix ETA. Independent advisories from other firms documented adjacent issues during the same period, including a path-traversal flaw tracked by Tenable as TRA-2025-47 that allowed arbitrary file reads through filename prompt injection.
The class is 'indirect prompt injection plus auto-approved network tool'. The fix has to come from the vendor: require human approval for outbound HTTP, sandbox file reads to a safe list, or both. Until that lands in a released version, the safe assumption is that any untrusted text Cascade processes can become an instruction.
How does build-time inlining work in Vite and Next.js?
The pattern is the same in both. The bundler walks your source code at build time and looks for process.env.X (or import.meta.env.X in Vite). If the variable name matches the prefix policy, the bundler replaces the expression with a literal string. If not, the expression is stripped or left as a Node.js-side reference that never reaches the browser.
The substitution is purely textual. There is no runtime evaluation, no per-user check, no environment-aware switching after the build. A next build run with NEXT_PUBLIC_STRIPE_SECRET_KEY set in the environment produces JavaScript files where that string is a literal, regardless of who downloads the bundle, what region they are in, or whether they are authenticated.
This is why the prefix policy matters more than the file location. A .env.local file outside the repository, a CI variable injected at build, and a value pasted into a Vercel dashboard all behave identically once next build runs: the prefix decides, not the source.
| Variable name | Source file | Where it lives after build |
|---|---|---|
DATABASE_URL | .env.local | Server-side process.env, not in browser bundle |
NEXT_PUBLIC_SUPABASE_ANON_KEY | .env.local | Inlined as a literal in every client chunk that references it |
VITE_API_BASE_URL | .env | Inlined as an import.meta.env.VITE_API_BASE_URL substitution |
STRIPE_SECRET_KEY (no prefix) | .env | Server-side only; bundler strips it |
NEXT_PUBLIC_STRIPE_SECRET_KEY (wrong prefix) | .env.local | Inlined as a literal, visible to every visitor |
The last row is the realistic failure mode. Cascade does not invent the prefix on purpose, but in a hurry it sometimes mirrors a naming pattern from elsewhere in the codebase, and the build accepts whatever you give it.
What configuration keeps Cascade away from .env?
Three controls, in order of effort.
First, the .codeiumignore file. Windsurf supports a .codeiumignore and respects .gitignore for indexing in recent versions, with caveats around already-indexed files. Adding .env* to .codeiumignore removes the file from the indexed context Cascade uses. The agent can still be asked to read the file directly through a tool call, but the file stops being part of the default context window.
Second, secret management outside the repository. Move secrets into a vault accessed by your CI (1Password, Doppler, GitHub Actions secrets, Vercel environment settings) and keep only placeholders in .env.example. The agent can read .env.example safely because it contains no real values.
Third, MCP server hardening. The Windsurf Cascade MCP documentation describes how MCP servers are configured and notes that the filesystem MCP server can restrict access to a list of allowed directories. If you wire third-party MCP servers into Cascade, narrow their access surface. For builders who want an external automated read of their compiled mobile build before submission, PTKD.com (https://ptkd.com) is one of the platforms focused on pre-submission scanning aligned with OWASP MASVS, which catches embedded credentials that survived the AI editor stage and ended up inside an APK, AAB, or IPA.
What to watch out for
A first mistake is assuming the question reduces to 'is Cascade malware'. It is not. The risks are structural and shared across AI editors with auto-approved tool access, including the patterns reported in Cursor, Cline, and Google's Antigravity in 2025 research.
A second mistake is treating the prefix as a safety check. VITE_ and NEXT_PUBLIC_ are inclusion rules, not safety rules. They include any variable with the prefix in the browser bundle. A developer who renames SUPABASE_SERVICE_ROLE_KEY to NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY for convenience has shipped that key to every visitor of the page that references it.
A third mistake is assuming server-rendered apps avoid the issue. Server-side rendering helps, but any <script> tag populated through templating, any dangerouslySetInnerHTML call with config, or any client component that imports a module that reads the secret pulls the value back into the bundle.
A fourth mistake is trusting that 'Codeium is a vendor, so this is fine'. Vendor trust is a real layer, but it does not help against prompt injection from a third party inside the editor session. The exfiltration in the Embrace The Red disclosure sent data to an attacker server through Cascade's own approved tools; Codeium was the carrier, not the destination.
Key takeaways
- Cascade does not automatically ship
.envto the browser; the bundler decides, and only prefixed variables get inlined. - The realistic build-time leak is a wrong prefix (
NEXT_PUBLIC_,VITE_) on a secret, often suggested by AI completions that mirror existing naming in the repository. - The realistic runtime leak is indirect prompt injection through files Cascade processes, documented by Embrace The Red in August 2025, with no patch ETA at disclosure time.
- Use
.codeiumignore, vault-based secret storage, and narrowed MCP server access to reduce the surface; treat.gitignoreas orthogonal to IDE indexing. - For teams shipping mobile builds with secrets that survived the editor and CI, an external scan of the final APK, AAB, or IPA aligned with OWASP MASVS is a reasonable backstop; platforms like PTKD.com (https://ptkd.com) focus on that pre-submission step for no-code and vibe-coded apps.



