A generated abstract illustration on a dark navy field: a small amber server cube at left emits a thin cyan line of glyph-like shapes that passes straight through a tall translucent blue glass membrane and continues to a dark terminal pane at right, where a single amber cursor block glows. The line is unbroken. No text, people or organisation logos appear. The OrcaRouter logo is composited in the bottom-right corner.
AI Safety Incidents

OpenCode's MCP Sign-In Handed a Server's URL to PowerShell — and No CVE Exists to Flag It

Author

Magnus Corvin

Date Published

Latest models · 20View all models →
Benchmarks: Artificial Analysis · updated daily
Back to all posts

On 19 October 2026 Pillar Security disclosed a remote code execution flaw in OpenCode, the open-source coding agent maintained by Anomaly: a remote Model Context Protocol server that a developer had configured could run arbitrary code on that developer's own machine during the MCP OAuth sign-in, with no consent prompt in between. The bug was confined to Windows and the Windows Subsystem for Linux, where OpenCode handed the server-supplied login URL to a PowerShell command without escaping it. Pillar puts the affected range at 1.0.137 through 1.18.32. Anomaly fixed it in 1.18.33, published to npm on 28 September 2026, and requested no CVE and published no advisory — so nothing in a normal vulnerability feed will tell an affected team to upgrade. Pillar reported no evidence the flaw was ever used in an attack. This is one record in the AI incident archive, where each entry carries its own sources, severity, confidence grade and disputed flag.

What the flaw actually was

When an MCP client connects to a remote server that wants authorization, it runs an OAuth discovery handshake. The server answers with a 401 and a challenge pointing at its discovery documents, and one field in those documents — authorization_endpoint — tells the client where to send the user to sign in. It is a free-form string, and the party being authenticated is the party that chooses it.

In OpenCode 1.18.32 that string went from the wire to a shell. Pillar traced the path from the server's discovery document through the MCP SDK into oauth-provider.ts, mcp/index.ts and browser.ts, ending at open, the small package OpenCode uses to launch a browser. Nothing on that path checked the URL's scheme, and nothing compared it against the origin of the server the developer had configured. The handshake is automatic by design — the whole point is to send you to a login page without making you copy a URL — so no approval step stood between the server's answer and the launcher.

The launcher is where it broke. On macOS and Linux, open passes the address as an argument vector and no shell is involved. On Windows, version 10.1.2 of open — the version every affected OpenCode release pinned — builds a PowerShell command, base64-encodes it and runs it with powershell -EncodedCommand. Pillar quotes the source: the application name is escaped on one line, and the target URL is not. PowerShell evaluates $(...) subexpressions inside double-quoted strings, so an address of the form https://evil.test/$([IO.File]::WriteAllText('C:\Users\Public\pwned.txt','RCE')) runs before the browser launch fails. OpenCode discards that failure.

Two properties made it easy to miss. The payload contains no spaces, so URL normalisation leaves it intact, and it is a syntactically ordinary https address. And the server did not have to be hostile when it was configured: Pillar notes that a later compromise, a hijacked registry entry, a typosquat or an expired domain would each turn a trusted configuration entry into a delivery mechanism.

Who was exposed

The exposed population is Windows and WSL users running OpenCode with a configured remote MCP server. Pillar describes OpenCode as having roughly 3 million weekly npm downloads and 211,000 GitHub stars; Infosecurity Magazine's report puts the star count at over 218,000. Neither figure is a count of affected installations, and nobody has published one.

The trigger is the one point where the two primary accounts diverge, and it matters for both risk and severity. Pillar describes exploitation as requiring no additional user interaction or consent. The Hacker News, in its 22 October report, says the browser step runs only when a developer starts the sign-in — by running opencode mcp auth or making the matching request — and that merely having the server configured, or opening a session, does not reach it. Either way the developer does nothing unusual; starting authentication against a server already in the configuration is routine. But "no interaction" and "one routine interaction" are different claims, and the difference feeds directly into the score.

The fix arrived described as a refactor

Pillar reported the flaw privately through a GitHub Security Advisory on 29 August 2026, with full reproduction material. On 25 September it followed up outside the advisory thread; Anomaly confirmed the report had reached its team and replied that malicious MCP servers fell outside its threat model. The same day, pull request #51414 — merged as commit 29f07e0c — landed. It is described as consolidating eight browser-launch call sites into one helper. Version 1.18.33 reached npm three days later, on 28 September.

The patch has three layers. The open dependency moved to 11.0.4, which wraps the target in single quotes, and PowerShell does not expand anything inside single quotes. A new openUrl() helper rejects non-HTTP(S) schemes. A scheme check went into redirectToAuthorization itself, at the boundary Pillar had named in its report. Neither the pull request nor the release notes mention a security flaw, and Anomaly requested no CVE.

The Hacker News reports that Anomaly's published security policy states that MCP servers a user configures are "outside our trust boundary," and that the company has issued advisories for other OpenCode code-execution flaws this year, including one fixed in August. Pillar's account of the reply it received is blunter: "we've updated the dependency, but generally, trying to deal with a malicious MCP server is outside our threat model."

An HTML timeline card titled 'How a five-year-old escaping bug reached OpenCode', subtitled 'Dated entries from Pillar Security's report and the open package's own issue history', listing nine rows: 22 October 2020, open issue #202 reports that a URL containing a dollar sign breaks on WSL 2; 18 October 2023, issue #323 titles 'OS command injection on windows when opening urls'; 9 July 2025, CVE-2025-6514 in mcp-remote, same sink, CVSS 9.6; 15 November 2025, open 11.0.0 quotes the PowerShell target; 7 December 2025, OpenCode calls open() with a server-supplied URL; 29 August 2026, Pillar reports privately via GitHub Security Advisory; 25 September 2026, pull request #51414 merged; 28 September 2026, OpenCode 1.18.33 published to npm, no CVE and no advisory; 19 October 2026, Pillar publishes. A footer cites Pillar Security and the open repository.

Read as a sequence, the timeline puts the OpenCode bug at the end of a five-year trail rather than the start of one. The defect that produced it was already public, and its fix had already shipped, before the line that used it was written.

Why scheme validation would not have stopped it

The agreed remedy for this class of bug is URL scheme validation: block the strange schemes, allow http and https, stop. It is what the MCP TypeScript SDK ships, and it is what OpenCode added in 1.18.33. Pillar's payload passes every one of those checks, because it is https. The SDK's denylist blocks javascript:, data: and vbscript:; a stricter http/https allowlist was proposed in SDK pull request #841 in August 2025 and closed without merging, while pull request #877 shipped the three-scheme denylist in v1.17.4 — and Pillar says that was still the policy in SDK 1.32.0 when it published. What actually closed the hole in OpenCode was the dependency bump, not the checks that look like the security fix.

The history argues against treating this as one project's slip. The open package has carried a README warning since 2021 that it makes no security guarantees and that sanitising input is the caller's job. In October 2020 a user filed issue #202 reporting that a URL containing a dollar sign lost part of itself on WSL 2 — the string expansion, filed as a broken-link annoyance. In October 2023 an Adobe engineer filed issue #323, "OS command injection on windows when opening urls," with a one-line proof of concept: open('https://$(calc.exe)'). The maintainer quoted the README and said pull requests improving the escaping were welcome; the issue was closed as not planned three days before open 11.0.0 shipped the escaping anyway, on 15 November 2025. OpenCode wrote its browser-launch call on 7 December 2025, three weeks after the fixed version of open existed, against a pin that was already months old.

In the months before that call was written, the MCP ecosystem logged three CVEs on the same sink or the same field: CVE-2025-6514 in mcp-remote (CVSS 9.6, disclosed by JFrog on 9 July 2025), CVE-2025-58062 in openmcp-client, and CVE-2025-10619 in sequa-mcp. Pillar's contrast is with clients that never build a shell command from a remote string at all: it names gemini-cli, Claude Code, github-mcp-server and Docker's mcp-gateway as passing the URL as an argument vector, which makes the question of what the string contains stop being load-bearing.

A generated abstract illustration on a dark navy field: a long cyan ribbon of abstract glyph shapes runs left to right and splits in two at a hollow chrome ring, which the upper branch passes straight through while the lower branch curves downward into a glowing amber terminal rectangle at bottom right. A faint dotted outline of an empty browser window floats in the upper right. No text, people or organisation logos appear. The OrcaRouter logo is composited in the bottom-right corner.

What is established, and what is not

The record is graded confidence A by the archive, and the reporting behind it holds up. Infosecurity Magazine published on 20 October with its own interview with Pillar's Eilon Cohen; The Hacker News published its own account on 22 October; DKCERT, Denmark's national CERT, summarised the finding on 21 October citing Infosecurity; and the Cloud Security Alliance's research lab published an analysis that adds the one substantive caveat below. None of these is the reporting party, and they agree on the mechanism, the versions and the silent fix. Anomaly itself has published nothing about the flaw.

Established, on the record:

• The defect, its mechanism and its platform scope. Pillar identifies specific source lines and the fix is visible in the public 1.18.32-to-1.18.33 diff; the two independent news accounts describe the same data flow.

• The affected range, 1.0.137 through 1.18.32, and the fixed release, 1.18.33, published 28 September 2026.

• That no CVE and no advisory exist. This is checkable, and it is the load-bearing fact for defenders.

• That no exploitation has been reported. Pillar says it saw no signs of use in attacks, and The Hacker News notes that no indicators of compromise were published. Absence of published indicators is not proof of absence, and without telemetry from the vendor neither reading can be confirmed.

Not established, or in tension:

• The 9.8. That number is Pillar's proposed CVSS v3.1 score, not an official one: with no CVE there is no NVD score and no vendor score. The Cloud Security Alliance's research note points out that 9.8 assumes no user interaction, and that if The Hacker News's account of the trigger is right, a rating with user interaction required — approximately 8.8 — would fit better. This piece does not settle that; the archive's own high-severity tag is a classification, not a score.

• The publication date. Pillar's report is dated 19 October 2026 in its header, and both news accounts use that date; the disclosure timeline at the foot of Pillar's own report lists publication as 4 October. The archive records 19 October at day precision.

• The size of the exposed population. No count has been published. The download and star figures above are repository metrics, not installations.

• Whether any machine was actually compromised. Nothing published supports it, and the record carries no real harm.

An HTML card titled 'Established, and not', split into two columns. The left column, headed 'Established', lists: affected versions 1.0.137 to 1.18.32, Windows and WSL only; fixed in 1.18.33 on 28 September 2026; no CVE and no security advisory issued; no exploitation reported and no indicators published. The right column, headed 'Not established', lists: official severity, since 9.8 is Pillar's proposed score with no CVE to attach it to; the publication date, 19 October in the report header and 4 October in its own timeline; the number of exposed installations; whether any host was compromised. A footer cites Pillar Security, The Hacker News and the Cloud Security Alliance research note.

What changed, and what to do

The remediation is a version check, because nothing else will tell you. OpenCode 1.18.33 or later is fixed. Affected installations have to be found by inventorying the package directly: Pillar's recommendation is to inventory OpenCode itself rather than wait for a feed, and the Cloud Security Alliance note suggests querying the opencode-ai package version, since there is no identifier for a feed to match. Teams that cannot upgrade and run Windows or the Windows Subsystem for Linux should remove remote MCP servers they have not vetted from their OpenCode configuration; opencode mcp list shows which servers are present.

For anyone maintaining an MCP client, Pillar's guidance is narrower than the usual advice: pass URLs as an argument vector and never build a command line from a remote string, bind OAuth discovery to the origin of the server the user configured, and treat discovery documents, server metadata and tool descriptors as untrusted input rather than as settings. The Cloud Security Alliance note adds hunting heuristics — an OpenCode process spawning powershell.exe with -EncodedCommand, for instance — while stressing that these are suggestions for detection engineering, not published indicators of compromise.

Not the Console breach

Pillar's disclosure landed days after Anomaly confirmed a separate breach of OpenCode's hosted Console, which may have exposed stored API provider keys. The two events are not connected, and Pillar's Eilon Cohen was explicit about the difference in his interview with Infosecurity Magazine. "The breach hit a legacy system behind a hosted key proxy, and exposed provider keys users had stored there," he said. "The vulnerability we reported runs the other way: a malicious remote MCP server executing code on a developer's own machine during the OAuth handshake. Different target and attacker position." The Console breach is a separate record in the archive, and the two should be read as separate entries.

What links them, in Cohen's framing, is the question underneath both: "Who you let hand credentials and inputs to an AI coding tool, and what that tool does with them."

The disclosure gap is the part that outlasts the bug. A flaw its finders rate critical, fixed inside a dependency bump, and absent from every automated signal a defender normally relies on leaves direct inventory as the only detection method — and the vendor published no advisory telling anyone to run one.