TL;DR

CVE-2025-62353 (CVSS 9.8) — HiddenLayer found that Windsurf's Cascade agent followed instructions hidden in a project's README.md to change its workspace path to the filesystem root (/ or C:\) and then use write_to_file (or its read sibling) to read and write arbitrary files on the developer's machine — even with Auto-Execution OFF and write_to_file on the explicit deny list. The classic "confused deputy": Cascade has the user's privileges and faithfully carried out an attacker's text. Affects all Windsurf ≤ 1.12.12. Distinct discrete bug from Windsurf zero-click MCP RCE (CVE-2026-30615). Update Windsurf and treat any repo you ever opened with old Windsurf as a potential exfil surface.

What happened

HiddenLayer demonstrated indirect prompt injection against the Cascade AI agent inside Windsurf. Their PoC placed natural-language instructions inside an HTML comment in a project's README.md — invisible to a human reader, but plain text to the model. When Cascade processed the README during routine code analysis (not a deliberate user action), the embedded prompt did two things:

  1. Changed Cascade's workspace path to the filesystem root (/ on Linux/macOS, C:\ on Windows).
  2. Directed write_to_file (and the equivalent read tool) at a path well outside the original project — ~/.ssh/id_rsa, ~/.aws/credentials, browser cookie stores, etc.

Cascade obeyed both. The auth/permission layer that should have caught this never fired: the deny-list check used Cascade's current workspace, which the injection had already rewritten (HiddenLayer-credited writeups via Vibe Graveyard, Witness AI).

Two properties make this a sharp class: - Auto-Execution OFF did not help. The tool-deny check ran on the wrong scope. - write_to_file on the deny list did not help. Same scope confusion (Vibe Graveyard).

Same "two parsers, one string" family as the Claude Code argv-smuggling deeplink RCE, Claude Code SOCKS5 null-byte sandbox bypass, and Starlette BadHost (CVE-2026-48710): the validator and the executor disagreed on the canonical value, the security check ran on the wrong one.

Am I affected?

# Windsurf version
windsurf --version
# or: Help → About inside the IDE

# Vulnerable: ≤ 1.12.12 (all versions, per HiddenLayer)
# Patched: see Windsurf changelog for the fixed release line after Oct 2025

If you ever opened an untrusted repo in Windsurf ≤ 1.12.12 — public clones, customer-submitted bug repros, contractor code — your local secrets were reachable. Even repos that look clean to a human can carry the payload because the injection lives in invisible-comment text.

# Quick local check for prompt-injection markers in README.md across repos
grep -RnE '<!--.*(ignore previous|system prompt|workspace|deny.list|write_to_file|/etc/|~/.ssh|~/.aws)' \
  --include 'README*' ~/projects 2>/dev/null

# Also grep for zero-width Unicode in agent-touched files (cf. TrapDoor)
perl -nlE 'print "$ARGV:$.:$_" if /[\x{200B}\x{200C}\x{200D}\x{FEFF}\x{2060}-\x{206F}]/' \
  $(find ~/projects -name 'README*' 2>/dev/null) 2>/dev/null

If you are affected

  1. Upgrade Windsurf to the latest release (Windsurf shipped a fix; pin to the current available version — silent auto-update is fine for security but lagged installs are exposed).
  2. Rotate every credential reachable from the developer machine. SSH keys, cloud profiles, GitHub/GitLab PATs, browser-stored session cookies, npm/PyPI tokens.
  3. Audit any repo you opened in Windsurf ≤ 1.12.12 for invisible-comment or zero-width-Unicode prompt injection in README/CONTRIBUTING/.cursorrules/AGENTS.md/CLAUDE.md/WINDSURFRULES.md. Same write-target surface as TrapDoor.
  4. Don't open arbitrary repos in an AI IDE with cloud creds loaded. Use a fresh user profile, a devcontainer, or a separate machine for untrusted code.

Prevention

prevention/agent-sandboxing.mdprevention/mcp-hygiene.md

Pattern to internalize: an AI agent that can change its own workspace scope from text inside a file it's reading has no usable permission model. The deny list runs on the current scope; the injection rewrites the scope; deny list fails open. The structural fix is to bind security decisions to the initial user-confirmed workspace and refuse mid-session scope mutations from agent input — the same lesson as Starlette BadHost (canonical scope is the security boundary, not the derived/rebuilt one).

Sources