- Book: System Design Pocket Guide: Interviews
- The series: Pocket Guides for Developers — 8 short books on agents, RAG, prompts, observability, events, databases and system design — the whole series
- My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools
- Me: xgabriel.com | GitHub
Run your dependency scanner against a laptop with opencode 1.18.32 on it. It finds nothing. According to Pillar Security's write-up, on Windows and WSL that version let a remote MCP server you had added run PowerShell on your machine during the MCP OAuth sign-in, "without additional user interaction or consent."
The bug is fixed. opencode 1.18.33 closed it on September 28. The pull request that did it is titled "refactor(core): share a browser opener across opencode and tui". No CVE was issued and no advisory was published, so, in Pillar's words, "this will not show up in your scans or your dependency alerts."
We keep treating coding-agent CLIs like libraries: pin a version, let a scanner tell us when to move. That model needs a CVE to work, and agent vendors often don't file one. Treat agent CLIs like browsers instead. Fast updates, a version floor, and an inventory you keep yourself.
What Pillar found
opencode is the open-source coding agent from Anomaly. Pillar puts the affected range at 1.0.137 through 1.18.32, on Windows and WSL only. macOS and Linux were not affected.
The path, as Pillar describes it, runs like this:
- A remote MCP server answers opencode's OAuth discovery request. The
authorization_endpointfield is a string the server picks. - opencode passes that URL to the
opennpm package (version 10.1.2) to launch your browser. - On Windows,
open10.1.2 hands the target to PowerShell. PowerShell expands$(...)inside double-quoted strings. - The URL is a well-formed
https://address with no spaces, so a scheme check doesn't stop it. The browser launch fails, but the injected expression has already run.
You don't install anything malicious and nobody injects a prompt. You add a remote MCP server, and the OAuth handshake starts by itself. Pillar rates it 9.8 on a CVSS vector it proposed. That is the researcher's score, not an official one, because there is no CVE to attach a score to.
Anomaly's side deserves a fair hearing. Pillar's timeline says the report went in privately on August 29. Anomaly answered on September 25, after Pillar followed up outside the advisory thread: "we've updated the dependency, but generally, trying to deal with a malicious MCP server is outside our threat model." The fix merged that same day and shipped three days later, and it is not a one-line patch. The PR bumps open to 11.0.4, routes every browser launch through one helper that only accepts http and https URLs, and adds a scheme check where the OAuth URL is handed off.
The threat-model argument is the part I don't buy. You add an MCP server to get tools, not to give it a shell on your laptop. Pillar also points out that "the server did not need to be malicious when configured," so a server that turns hostile later reaches the same path. The same bug class in mcp-remote got CVE-2025-6514, rated critical at 9.6, in July 2025. One project got a CVE for it. The other got a refactor.
Why your scanner says you're fine
Dependabot alerts when "a new vulnerability is added to the GitHub Advisory Database," and the docs add: "Only advisories reviewed by GitHub trigger alerts." No advisory, no alert.
There's a second gap. Dependabot scans your repository's default branch. An agent CLI installed with curl, Homebrew or npm -g on a developer's machine usually isn't in any repository's dependency graph at all.
And the release notes won't tip you off either. The 1.18.33 entry for this change reads: "MCP browser launch failures are now reported when the launcher exits immediately." That is true, and it's not what a security team would search for.

A scanner checks the list it was given. A fix with no CVE isn't on that list.
opencode isn't an outlier. Adversa AI's catalog of ten documented attacks involving Claude Code, published September 23, says: "Two entries on this list produced CVEs." Its summary: "So of ten working attacks, your vulnerability scanner sees two, your SBOM sees none." One of the eight without a CVE, Plugin4Shell, was "Patched in 2.1.179 ... with no CVE assigned." Four carry a vendor declination on the record, two of them from Anthropic and the rest from other vendors. Adversa is careful to add: "None of that is bad faith on anyone's part."
I agree with that. Nobody is hiding anything. The tooling we use to decide when to update assumes security fixes get CVEs. Going by Adversa's count, agent CLI fixes often ship without one.
Treat agent CLIs like browsers
A browser fetches untrusted content all day and runs code from it. So does a coding agent: web pages, issues, READMEs, MCP servers, other people's repos. Most of us stopped pinning browsers years ago. Chrome "can automatically update when a new version of the browser is available," and "the update applies the next time you restart Chrome." Nobody waits for a CVE before taking a Chrome update.
Agent CLIs are halfway there, and it depends on the vendor and the install method:
- Claude Code native installs "automatically update in the background." Homebrew, WinGet, apt, dnf and apk installs don't, by default. You can pick the
latestchannel orstable, which the docs describe as "typically about one week old, skipping releases with major regressions." - opencode checks for new versions and shows a notice, but "Updates are never installed automatically." You run
/updatein the TUI oropencode upgrade.

Browser-style: updates on by default, on a channel you chose, with a floor you enforce.
Browser-style, for an agent CLI, means three things.
Updates on by default. A stable channel is fine. The point is that you move without waiting for a CVE.
A floor you enforce. Claude Code has a minimumVersion setting that stops updates from installing anything below it, and managed settings add requiredMinimumVersion, which makes Claude Code "refuse to start on a version older than your organization requires." This is the example from the docs:
{ "autoUpdatesChannel": "stable", "minimumVersion": "2.1.100" } An inventory you keep yourself. Pillar's advice for opencode is blunt: "Finding it means inventorying opencode directly."
Fast updates carry their own supply-chain risk: a bad release reaches you fast too. A stable channel is the answer to that. Signed releases cover a different case, a tampered binary (Claude Code publishes a GPG-signed manifest of checksums, per its setup docs). Pinning is fine if someone owns the pin and moves it. The trouble is a pin nobody looks at again.
Inventory what you actually run
This is a plain shell loop for macOS, Linux and WSL. It prints the first line of each agent's --version output, or says the agent isn't installed:
for cli in claude codex opencode; do if command -v "$cli" >/dev/null 2>&1; then v="$("$cli" --version 2>&1 | head -n 1)" printf '%s: %s\n' "$cli" "$v" else printf '%s: not installed\n' "$cli" fi done And a floor check for opencode, using the first fixed version from Pillar's report:
min="1.18.33" have="$(opencode --version 2>/dev/null \ | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" low="$(printf '%s\n%s\n' "$min" "$have" | sort -V | head -n 1)" if [ -z "$have" ]; then echo "opencode not found" elif [ "$low" != "$min" ]; then echo "opencode $have is below $min: run opencode upgrade" else echo "opencode $have: ok" fi From inside WSL, a native Windows install of opencode may not show up, or WSL may find the Windows copy instead, so check both if your team uses both. If you run a fleet, put the same check in whatever already reports software versions from developer machines. If you can't upgrade a Windows or WSL machine yet, Pillar's fallback is to remove unvetted remote MCP servers from your opencode config.
Where Hermes fits
I build Hermes IDE, so weigh this section with that in mind. By default, Hermes runs each agent's own interface in a real terminal, opencode included, "exactly as it would anywhere else," as the README puts it. So when you run opencode upgrade, your next opencode session in Hermes runs the version you just installed. There's no Hermes release you have to wait for before the vendor's fix reaches you.

Hermes 2.3.4: the ⌘N New task sheet with its agent picker open. Claude Code (installed, 2.1.299) is selected, Codex is installed (0.145.0), and the other supported agents, OpenCode among them, are marked Not installed, plus Custom agent.
As the screenshot shows, the agent picker also lists which agents are installed and the version it found for each. It covers one machine. For a fleet you still need the check above. Hermes doesn't update your agents for you and it isn't a vulnerability scanner. Updating is still your job, and your vendor's.
Hermes is free to download, source-available under BSL 1.1, and runs on macOS, Windows and Linux. It isn't affiliated with Anomaly, Anthropic, OpenAI, Nous Research or any other agent vendor. Download it or read the code on GitHub.
So, CVE or refactor?
The next fix like this may not be in opencode. It could be in whichever agent CLI you installed with npm -g months ago and haven't updated since.
Do you pin your agent CLIs, or let them update? And if a vendor fixes a no-consent RCE without a CVE, is that a refactor or an advisory? Tell me in the comments.
If this was useful
The question under all of this is where a system draws its trust boundaries, and what happens when one moves without anyone saying so. The System Design Pocket Guide: Interviews walks through 15 real system designs step by step, trade-offs included, which is good practice for asking that question before a researcher does. It's one of 8 short books in Pocket Guides for Developers, covering agents, RAG, prompts, observability, events, databases and system design.



