The Login Page Was The Attack: No CVE, No Advisory, And A Fix Shipped As A Refactor

A developer adds a remote MCP server to their coding agent, runs the sign-in command, and the browser handoff runs the attacker's code on their Windows machine. No malicious package was installed. No prompt injection touched the model. The attack surface was the login page itself, and the code executed with the developer's full privileges.
That is the finding Pillar Security published on 4 October 2026 about OpenCode, an open-source coding agent with roughly three million weekly npm downloads, and it lands in the middle of the hardest unresolved question in MCP security: whose job is it to distrust the server? The company behind it, Anomaly, fixed the flaw quickly and well, in version 1.18.33 released on 28 September. What it did not do is request a CVE, publish an advisory, or mention security in the release notes, on the stated position that malicious MCP servers fall outside its threat model. The result is a vulnerability that is fully public in the code diff and invisible to every scanner and dependency alert that defenders rely on.
This article covers what the flaw was, why the standard MCP defence did not stop it, the five-year paper trail behind the dependency at its centre, what the vendor did and did not do, and the checks that matter for any team running coding agents on Windows. Everything comes from Pillar's own report, read in full, and the published fix history.
What the flaw was
The path ran through the OAuth sign-in that remote MCP servers use. When such a server wants authorization, the MCP client runs a discovery handshake, and the server's documents name the address where the user should be sent to log in. That address, the authorization endpoint, is a free-form string chosen by the server.
In the affected versions, OpenCode passed that string to a helper package called open, which launches browsers. Pillar's analysis of the pinned version found that on Windows the target was placed inside a PowerShell command without escaping, and PowerShell evaluates subexpressions written between parentheses inside double-quoted strings. A server-controlled address containing such an expression ran as code, even though the browser launch itself then failed, and the failure was discarded.
Three properties make this finding stand out from the usual vulnerability writeup.
No extra consent was needed. The code executed during the sign-in the developer chose to start. Pillar notes that merely configuring a server did not trigger it, but the sign-in itself was sufficient.
The server did not need to be malicious when it was added. The payload arrived in a response at connection time, so a later compromise of the server, a hijacked registry entry, a typosquat, or an expired domain re-registered by someone else could deliver it. Trust extended at configuration time does not cover what the server returns months later.
Only Windows was exposed. The flaw affected Windows and the Windows Subsystem for Linux, in versions 1.0.137 through 1.18.32. macOS and Linux were not affected, because the launcher package takes a different code path there.
Why the standard defence did not work
The agreed remedy for this bug class, after a similar flaw in a proxy package in July 2025, has been URL scheme validation: reject exotic schemes, allow http and https. Pillar's payload defeats that by being a perfectly ordinary https address with no spaces. It passes the scheme check that OpenCode added in the fix, and it passes the scheme denylist that the Model Context Protocol SDK ships as its default today.
Pillar traces the history, and it is the most instructive part of the report. The underlying behaviour was reported in 2020 as a cosmetic bug, because a URL containing a dollar sign misbehaved on WSL 2. In 2023 an Adobe engineer filed a command-injection report with a one-line proof, and the launcher's maintainer answered by quoting his README, which since 2021 has stated that the package makes no security guarantees and that sanitising untrusted input is the caller's job. That answer is accurate: the package is a launcher, launching what you hand it is its entire contract, and nobody files CVEs against a shell-execution function for executing what it is given.
The escaping fix landed in the launcher's version 11.0.0 in November 2025. OpenCode had written its call to that launcher on 7 December 2025, three weeks after the fixed version shipped, pinned to the older version, and the pin was never revisited for ten months. Pillar does not call this negligence, and neither will I: dependency pins freeze yesterday's security posture into today's build, silently.
The same defect class had already been published in three CVEs during 2025, all naming the same sink, before OpenCode wrote the vulnerable line. And in the middle of that window, the MCP SDK community debated the fix: a proposal to allow only http and https was closed without merging, replaced by a denylist of three schemes, which remains the SDK's policy and which the payload sails through.
The fix, and what actually closed the hole
Credit where Pillar gives it: Anomaly's fix was fast and better than it needed to be. Merged on 25 September and released in 1.18.33, it added defence at three layers: the launcher dependency was bumped to the escaping version, a new URL-opening function rejects non-https schemes, and a scheme check was added at the exact boundary the report named.
But Pillar's testing shows the scheme checks would not have stopped the payload. What closed the hole was the dependency upgrade, because the new launcher version wraps its target in single quotes, and PowerShell expands nothing inside single quotes. The vendor dismissed the dependency bump as incidental to a refactor, and it was the actual fix. If your team added scheme validation after the 2025 disclosures and still pins the older launcher version, the check is a seatbelt on a door that opens anyway.
Pillar also lists MCP clients that handle this correctly, and the common property is not the scheme check. It is that they never build a shell command out of a remote string at all: they pass arguments as an argument vector, or they take authorization endpoints from the operator rather than from the peer. Claude Code is listed among the clients that guard the opener so the OAuth path cannot reach it with a server-controlled value.
The disclosure gap, stated plainly
The technical fix is the smaller part of this story. The larger part is what happened around it.
Anomaly fixed the issue after private disclosure, shipped the change in a pull request presented as consolidating browser-launch call sites, released it three days later, requested no CVE, and answered the researchers that malicious MCP servers are outside its threat model. Its published security policy places user-configured servers outside the trust boundary.
Pillar's response to that position is the sharpest thinking in the report, and it deserves the quote: an MCP client is a parser handling data from an untrusted remote peer, running unsandboxed with a developer's full privileges, and most of what it parses it handles long before the model wakes up. That is the same category as a browser or a mail client, both of which treat remote servers as hostile by default. Whether a server is trusted is a business decision, and the vendor's threat model decides what your scanners can report. When the vendor places an input outside its model, your tooling inherits that decision, silently.
The practical consequence: there is no CVE to match, so vulnerability scanners and dependency bots will never flag affected installs. Finding them means inventorying OpenCode directly. Any version from 1.0.137 through 1.18.32 on a Windows or WSL host is affected, and Pillar saw no signs of exploitation and published no indicators for checking past compromise. The MCP ecosystem has a disclosure culture problem as much as a code problem, and this incident is a clean example of both.
What to do this week
Four checks, in the order Pillar sets out.
Inventory OpenCode on Windows and WSL, and upgrade. Version 1.18.33 or later. Because there is no advisory to match, the inventory has to be direct: check the machines, not the alerts. Note that OpenCode's current release line has moved well past this version, so most up-to-date installs are already safe; the exposure is in machines where the agent was installed once and forgotten.
If you cannot upgrade yet, remove unvetted remote MCP servers from the configuration until you can, or accept and document the exposure. The trigger requires starting a sign-in to a remote server, so the risk tracks the servers your team actually connects.
Review the remote MCP servers your coding agents trust, and who approved each one. A server that was safe when configured can change hands through a takeover, a typosquat or an expired domain, and the OAuth handshake will fetch whatever that server publishes at connection time.
If you build anything that opens URLs, audit the path. Two rules from Pillar cover it: never interpolate a remote string into a shell command, pass it as an argument instead, and bind OAuth discovery to the configured origin rather than accepting whatever endpoint the peer names. A scheme check is worth having, and it is not sufficient on its own.
The wider point connects to the themes of this month's coverage. The same protocol surfaces appeared in the semantic layer piece, where the tool surface is the boundary agents actually live behind, and the enforcement argument from the OpenShell article applies here with unusual force: a parser of untrusted remote input, running with developer privileges, is exactly the kind of component that needs its boundary defined outside itself. And the disclosure question echoes the Rank Math supply chain piece: in both cases, the most dangerous thing was not the flaw but the gap between what happened and what defenders could see.
The MCP trust question, stated plainly
The report's most quotable line, that an MCP client is a parser of untrusted input like a browser or a mail program, deserves unpacking, because it inverts how most teams reason about agent tooling.
When a team adds an MCP server to an agent's configuration, the mental model is usually installing an integration: a trusted component, chosen deliberately, that extends the agent. Pillar's framing is different and more accurate: a remote MCP server is a third party speaking a protocol to a process on your laptop, so every field in every response is attacker-controlled until proven otherwise, including discovery documents, tool descriptors and error strings, not just the obvious URLs. The agent's model is not the first consumer of that data, and it is nowhere near the only one.
Under that model, the questions change. Who approved each remote server, and when was that approval last revisited? What does the client do with a server-named authorization endpoint, and can a takeover of the server change it? Does the client treat error strings and metadata as data, or as instructions? The OpenCode incident answered the second question badly, and the vendor's threat model meant nobody was watching for it.
There is a parallel worth naming to the disclosure side. In the Claude Security coverage, the value of continuous monitoring was that findings track the code as it changes. Here the mirror image appears: a fix that ships quietly is invisible to every monitoring system built on advisories. Both point at the same dependency. Security signals that come from vendor announcements are only as complete as vendors choose to make them, and MCP tooling currently has more vendors choosing silence than choosing disclosure.
For teams that want a rule of thumb, the report's five lessons compress into one sentence: treat every MCP server response the way a browser treats a web page, as hostile input to a parser that runs with your privileges, and design the client so that parser never reaches a shell.
Where the numbers stop
- The usage figures, roughly three million weekly npm downloads and 211,000 GitHub stars, are Pillar's counts at publication.
- The claim that no exploitation was observed is Pillar's statement that it saw no signs of attacks and published no indicators for checking past compromise. Absence of published indicators is not evidence of absence.
- The characterisation of Anomaly's position comes from Pillar's account of the disclosure correspondence. The vendor's own words, as quoted, are that malicious MCP servers are outside its threat model; everything beyond that quote is interpretation.
- The affected version range, 1.0.137 through 1.18.32, is Pillar's determination. Versions on other platforms, or builds outside the npm distribution, were not covered in the report.
- I have not tested OpenCode, the launcher package, or the payload path, and no claim here is a hands-on finding.
FAQ
What is the OpenCode MCP sign-in vulnerability?
It is a remote code execution flaw in the OpenCode coding agent, affecting Windows and WSL in versions 1.0.137 through 1.18.32. During the OAuth sign-in to a remote MCP server, a server-controlled authorization URL was passed unescaped into a PowerShell command, so a crafted URL ran code on the developer's machine with their privileges. The trigger required starting the sign-in, and no prompt injection or malicious installation was involved.
Is there a CVE for it?
No. Anomaly fixed the flaw in version 1.18.33, released 28 September 2026, but did not request a CVE or publish a security advisory, and the change shipped in release notes described as a refactor. Because there is no advisory, vulnerability scanners and dependency alerts will not identify affected installations. The version range has to be checked directly on the machines that run the agent.
What is the actual fix?
Upgrade to OpenCode 1.18.33 or later, which upgrades the browser-launching dependency to a version that escapes its Windows target, adds a scheme check, and adds a check at the OAuth boundary. If upgrading is not possible, remove unvetted remote MCP servers from the configuration on Windows and WSL hosts. Teams building MCP clients should go one step further and pass remote URLs as arguments rather than building shell commands, since a plain https URL carries this payload past scheme validation.
The short version
A researcher found that OpenCode, a widely used open-source coding agent, ran server-controlled code on Windows during a routine MCP sign-in, because the login URL from the server was passed unescaped into PowerShell. The vendor fixed it in 1.18.33 within a month of private disclosure, but shipped the change as a refactor, requested no CVE, and stated that malicious MCP servers are outside its threat model, so scanners will never flag the affected versions. The deeper story is a dependency pinned three weeks before its own escaping fix shipped, a payload that passes every scheme check because it is an ordinary https URL, and the same defect class already published in three earlier CVEs. Check your machines directly, upgrade, review which remote MCP servers your agents trust, and if you build anything that opens URLs, keep remote strings out of shell commands entirely.
Sources
- Pillar Security, Open and Shut: Remote Code Execution in opencode via MCP OAuth, the research report covering the flaw, the payload path, the five-year history of the launcher bug, the vendor response and the disclosure timeline: https://www.pillar.security/blog/open-and-shut-remote-code-execution-in-opencode-via-mcp-oauth
- OpenCode, the changelog documenting releases after the fix, showing the current version line: https://opencode.ai/changelog