GUIDE · HARDENING 8 min ·

Hardening Windsurf and CascadeWhat to lock down after two bad CVEs

Windsurf shipped two reachable-by-prompt-injection CVEs in nine months: a CVSS 9.8 path traversal in its file tools and a zero-click MCP remote code execution. The default config does not defend against either. This is the configuration that does.

TL;DR· the answer, in twenty seconds

What happened: Windsurf shipped two prompt-injection-reachable CVEs. CVE-2025-62353 (CVSS 9.8, October 2025) let a poisoned file read and write anywhere on disk through Cascade's codebase_search and write_to_file tools. CVE-2026-30615 (CVSS 8.0, 2026) let attacker-controlled HTML register a malicious MCP server and run commands with zero user interaction.

The minimum fix: Set Cascade terminal commands to require approval, lock MCP server installation behind review, exclude secret paths from indexing with .codeiumignore, and patch to the current build. Re-verify after every update.

The lesson: Both bugs share one root: Cascade treats text it reads as instructions it can act on. Configuration narrows the blast radius. It does not remove the primitive.

Windsurf shipped two prompt-injection-reachable CVEs in nine months, and the default configuration does not defend against either.

The first was CVE-2025-62353, a path traversal that HiddenLayer published in October 2025 at CVSS 9.8, affecting all versions with no patch available at disclosure. The second was CVE-2026-30615, a zero-click MCP remote code execution that surfaced out of OX Security's research into the Model Context Protocol. Both are reachable through content Cascade reads on its own, without a developer clicking anything.

Windsurf is forked from VS Code and built around Cascade, an agent that searches your code, writes files, runs terminal commands, and registers tools. Most of that power is on by default. This guide covers the configuration that makes the two CVEs, and the class of bug behind them, survivable.

What to know in 60 seconds

  • Cascade can run terminal commands without asking. The auto-execution setting is the single highest-risk default in the product.
  • Cascade reads files during routine analysis. A poisoned README, issue, or fetched web page is an input channel Cascade can be steered by.
  • MCP servers live in ~/.codeium/windsurf/mcp_config.json. CVE-2026-30615 worked by writing a malicious server into that file and registering it with no prompt.
  • Indexing sends file contents to Codeium's models. .codeiumignore is the only thing that keeps a secret-bearing path out of that index.
  • Windsurf inherits VS Code's extension trust model and Chromium's CVE timeline. Both are your problem to patch.
  • Settings reset across updates. A hardened config is not a one-time task.

The two CVEs that should change how you configure Windsurf

Read both advisories before you decide your settings are fine.

CVE-2025-62353 lived in two of Cascade's built-in tools, codebase_search and write_to_file. Neither validated the file paths it received. HiddenLayer's proof of concept hid instructions inside a project's README.md using comments invisible to a human reader. When Cascade processed that file during normal analysis, the injected prompt reset the workspace path to the filesystem root and pointed write_to_file at a sensitive file in an unrelated directory. The developer approved nothing. They did not need to know the attack was running. Cascade acted as a confused deputy, carrying out instructions that came from the attacker rather than the person at the keyboard.

CVE-2026-30615 is the one that should worry you more. OX Security found an architectural flaw in MCP and tested it against Cursor, VS Code, Windsurf, Claude Code, and Gemini CLI. Windsurf was the only one where exploitation required zero user interaction. Attacker-controlled HTML, processed by Cascade, triggered an unauthorized write to the local MCP configuration and auto-registered a malicious stdio MCP server. That server then ran commands on the host. CVSS scored it 8.0; the zero-interaction property is what earns it a place at the top of your patch list.

Patch first. Confirm you are on a build that postdates both fixes, then apply the configuration below so the next disclosure lands on a hardened target.

Where Cascade reads untrusted input

Both CVEs depend on Cascade ingesting content an attacker controls. Once you see how many of those channels exist, the value of the auto-execution and MCP locks below stops feeling optional.

Cascade reads, and can be steered by, content from:

  • Files in the workspace it analyzes, including README.md, code comments, and config files. This is the HiddenLayer vector.
  • Web pages and HTML it fetches to answer a question. This is the CVE-2026-30615 vector.
  • Issue trackers, pull request bodies, and error payloads surfaced through MCP servers. A teammate's repo, or a stranger's open-source issue, becomes an input channel.
  • Tool output from any MCP server you connected, which Cascade trusts as much as your own typing.

None of these channels carries a trust label. To the model, an instruction inside a fetched web page reads the same as an instruction you typed. The hardening that follows works by making the dangerous actions, running a command and registering a server, require a human even when the instruction looks legitimate. Treat every one of these channels as attacker-reachable and the rest of the config follows.

Turn off Cascade auto-execution

Auto-execution lets Cascade run terminal commands without a confirmation prompt. WitnessAI's audit puts it plainly: it is a footgun, and rm -rf is one prompt away when it is enabled. Pair that with either CVE above and the attacker does not need a second step. The agent that reads the poisoned file is the same agent that runs the command.

Open Settings, find the Cascade section, and require approval before command execution. If you keep any form of auto-run for convenience, restrict it to an explicit allowlist of read-only commands and never include anything that writes, deletes, installs, or makes network calls.

A workable allow set for an auto-run list looks like this. Everything else asks first:

# Safe to auto-run: read-only, no side effects
git status
git diff
git log
ls
cat
grep
rg

# Never auto-run (require approval every time):
#   rm, mv, cp into system paths
#   curl, wget, nc, ssh
#   npm install, pip install, brew install
#   git push, git reset --hard
#   anything piped to sh or bash

The deny side matters more than the allow side. An allowlist that permits npm install hands a supply-chain payload a direct path to execution, because the install scripts run as you. Keep package installs and any network command behind a human approval every time.

Verify the setting after you change it, then verify it again after the next Windsurf update. Auto-execution defaults have moved between releases, and a setting that does not survive an update is not a control.

Lock down MCP server installation

The MCP config is the file that CVE-2026-30615 abused. Know what is in it:

cat ~/.codeium/windsurf/mcp_config.json

For every server entry, confirm four things:

  1. You added it on purpose. A server you do not recognize is the exact signature of the CVE-2026-30615 attack: a write you never made.
  2. The command is pinned to a version, not latest or a floating tag.
  3. You have read the server's source or seen a credible third-party audit.
  4. The server does not request filesystem or network scope beyond what its job needs.

Remove anything you are not actively using. Cascade caps active MCP tools at 100 and offers per-tool toggles inside the panel, so you can disable individual tools on a server you keep without dropping the whole server. Use that to shrink the surface to the tools you actually call.

The deeper fix is to treat mcp_config.json as a file an attacker wants to write to. On a shared or sensitive machine, watch it for changes you did not make:

# Snapshot the MCP config and alert on drift
shasum -a 256 ~/.codeium/windsurf/mcp_config.json > ~/.config/windsurf-mcp.sha256

# Later, or on a schedule:
shasum -a 256 -c ~/.config/windsurf-mcp.sha256 \
  || echo "MCP config changed since last review"

On Windsurf Teams and Enterprise, the admin allowlist restricts which MCP servers developers can install using regex matching against server IDs. If you run Windsurf across a team, configure that allowlist centrally. A per-developer policy that lives in one person's settings is not a policy.

Keep secrets out of the index with .codeiumignore

Windsurf indexes your workspace and sends file contents to Codeium's models for context. By default it skips .gitignore entries, node_modules, and dotfiles. That default is not enough, because plenty of secret-bearing files are not gitignored, and a path that is only in .gitignore can still be reached by the path traversal in CVE-2025-62353.

Add a .codeiumignore at your repo root. It uses .gitignore syntax, per the Windsurf docs:

# Secrets and environment
.env
.env.*
.env.local
*.pem
*.key
*.p12
*.pfx
secrets/
credentials/

# Agent and tool state
.codeium/
.cursor/
.claude/

# Infrastructure with interpolated secrets
terraform.tfstate
terraform.tfstate.backup
*.tfvars

Commit the file. Anyone who opens the project in Windsurf inherits the exclusions. For a machine that holds several repos, place a global .codeiumignore in ~/.codeium/ so the rules apply to every workspace without per-repo setup.

One caveat worth stating out loud: the ignore file shrinks the indexing surface, but the path traversal in CVE-2025-62353 reached files by absolute path, outside any project. Excluding .env from the index does not stop a write_to_file call that the agent was tricked into pointing at ~/.aws/credentials. That is why patching comes before ignoring.

Inherited risks: VS Code extensions and Chromium

Windsurf is a VS Code fork, and the fork inherits two things people forget about.

The first is extension trust. An extension you install in Windsurf runs with your permissions and can read your workspace, including whatever Cascade can see. Vet extensions the way you vet dependencies: check the publisher, the install count, the source, and the requested permissions. WitnessAI's audit flags inherited VS Code extension trust as one of the five things that catch Windsurf teams out, and supply-chain campaigns have targeted IDE extension ecosystems directly.

The second is Chromium. Windsurf ships an Electron runtime, so every Chromium security release is a Windsurf patch you owe yourself. There is no separate action here beyond keeping Windsurf current, but it changes how you read "I'll update later." A deferred update is a deferred browser-engine patch.

Enterprise controls worth turning on

If you run Windsurf across an org, the Teams and Enterprise tiers expose controls the individual app does not.

Privacy and zero-data-retention settings keep your code out of training pipelines and, on Enterprise, out of Codeium's retention entirely. The self-hosted Enterprise deployment runs models, indexing, and inference inside your network so code and telemetry stay in your VPC.

The MCP admin allowlist, covered above, is an org-level control. Set it once rather than asking every developer to police their own mcp_config.json.

Auto-execution can be disabled centrally through the admin portal so a single misconfigured laptop cannot run commands from a poisoned repo. Combine that with SSO and identity-provider deprovisioning, and a developer who leaves the team loses Windsurf access the moment their account is disabled.

These controls do not change the CVE math on their own. They make the hardened state the default for everyone instead of a thing each person remembers to do.

A hardening checklist you can paste into a PR

## Windsurf security hardening

- [ ] On a build that postdates CVE-2025-62353 and CVE-2026-30615
- [ ] Cascade auto-execution disabled (or restricted to read-only allowlist)
- [ ] Deny list covers installs, network commands, and pipes to sh
- [ ] ~/.codeium/windsurf/mcp_config.json reviewed; no unrecognized servers
- [ ] MCP servers pinned to versions, not latest
- [ ] Unused MCP servers and tools removed
- [ ] mcp_config.json change-monitored on shared/sensitive machines
- [ ] .codeiumignore at repo root, committed, covers .env / secrets / *.key
- [ ] Global ~/.codeium/.codeiumignore set on multi-repo machines
- [ ] Installed extensions vetted (publisher, source, permissions)
- [ ] Windsurf kept current for Chromium patches
- [ ] Enterprise: admin MCP allowlist, central auto-exec policy, SSO + deprovisioning
- [ ] Re-verify every setting after the next Windsurf release

Keep it in your team's SECURITY.md. Settings drift across updates, and a checklist that lives in one person's memory drifts with them.

What this means for your stack

Patch Windsurf today and disable Cascade auto-execution before you do anything else. Those two actions close the reachable path on both CVEs and cost about ten minutes. Everything else on the checklist narrows what a future disclosure can touch.

Both bugs share one root cause, and no setting removes it. A language model reads input as a single stream of tokens with no separation between instructions and data, so anything Cascade reads, Cascade can be told to act on. The architectural answer is to stop the agent's process from holding anything worth stealing in the first place. Secrets that sit as ambient environment variables or literal values in the workspace are available to Cascade the moment it runs, which means they are available to whatever instruction it just read.

A local credential broker holds secrets in an encrypted vault, injects them into a specific child process at exec time, and revokes access when that process exits. The agent gets a reference, not the value, and the audit log records every access. hasp is one working implementation: curl -fsSL https://gethasp.com/install.sh | sh, then hasp setup and connect a project so the next Cascade session sees a stub instead of your AWS key. Source-available (FCL-1.0), local-first, macOS and Linux, no account.

The configuration in this guide is worth doing whether or not you change your secrets model. The runtime change is what makes the third Windsurf CVE, whenever it lands, a smaller problem than the first two were.

Sources· cited above, in one place

NEXT STEP~90 seconds

Stop handing the agent your real keys.

hasp keeps secrets in one local encrypted vault, brokers them into the child process at exec, and never lets the agent read the value.

  • Local, encrypted vault — no account, no cloud, no telemetry by default.
  • Brokered run — agent gets a reference, the child process gets the value.
  • Pre-commit + pre-push hooks catch managed values before they ship.
  • Append-only HMAC audit log answers "did the agent touch the prod token?" in seconds.
→ okvault unlocked · binding ./api
→ okgrant once · pid 88421
→ okagent never read

macOS & Linux. Source-available (FCL-1.0, converts to Apache 2.0). No account.

Browse all clusters· eight threads, one index