# OpenCode Remote Code Execution via /global/upgrade Content-Type Confusion and Cross-Site Request (GHSA-632h-h47v-g4x4)

> The /global/upgrade endpoint of the OpenCode AI coding agent's local HTTP server parses text/plain bodies as JSON, does not validate Origin, and passes an attacker-chosen package specifier to npm/pnpm/Bun. A malicious webpage can submit a cross-origin form to the local server and make it install an attacker-controlled package whose lifecycle script runs code. Fixed in 1.18.22; no CVE was assigned.

- **Published:** 2026-11-12T00:55:21Z
- **Last reviewed:** 2026-11-12T00:55:21Z
- **Canonical:** https://intel.threadlinqs.com/threat/TL-2026-5809
- **Card image:** https://intel.threadlinqs.com/og/threat/TL-2026-5809.png
- **ID:** TL-2026-5809
- **Severity:** HIGH (CVSS 7.5)
- **Category:** VULNERABILITY
- **Status:** PATCHED
- **Detections:** 9 (1 shown free below) · **IOCs:** 6 (1 shown free below)

## Description

GHSA-632h-h47v-g4x4 (reported by Christophe Tafani-Dereeper of Datadog Security Labs) affects the npm package opencode-ai versions 1.14.30 through 1.18.21 when OpenCode is installed via npm, pnpm or Bun. The bug was introduced by PR #24853 (merged 2026-04-29) and first shipped in v1.14.30 (2026-04-30). Installations via curl, Homebrew, Chocolatey and Scoop are not affected by the arbitrary-package path.

Root cause is a chain of three weaknesses. (1) The /global/upgrade handler accepted a user-supplied 'target' field and passed it unvalidated to the package manager's global install command. Because npm accepts remote tarball URLs as well as version numbers, the attacker can point the install at a server they control; a preinstall lifecycle script in that package then executes on the victim's machine. (2) The endpoint used a raw handler (handleRaw) that parsed the request body as JSON without checking the Content-Type header, so a body sent as text/plain from an HTML form was accepted. (3) The server did not validate the request Origin, and browsers do not subject top-level cross-origin form navigations to CORS preflight or Chrome Local Network Access restrictions, so a web page could reach the local server (default 127.0.0.1:4096).

Exploitation requires that the victim runs the OpenCode server (opencode serve or opencode web) without password authentication, or that the browser holds cached credentials for it, and that the victim visits an attacker-controlled page while the server is running. Datadog demonstrated a working proof of concept against OpenCode 1.18.21. In-the-wild exploitation is not reported in the sources. Datadog observed 82 vulnerable versions with over 647,000 npm downloads between 2026-09-17 and 2026-09-23 (about 38.9% of downloads in that period); this does not indicate unique users or how many run the server.

The fix (PR #44686, released in 1.18.22 on 2026-08-24) requires 'target' to be a valid semantic version and switches the handler to one that honors Content-Type, so text/plain requests receive HTTP 415. Datadog reported the issue on 2026-08-11; at the vendor's request public disclosure was delayed one month to 2026-09-24. The GitHub advisory rates it High (CVSS 3.1 7.5) and lists CWE-346, CWE-352 and CWE-436. Mend.io tracks it as WS-2026-0073 (CVSS v3 7.5, CVSS v4 7.7).

## MITRE ATT&CK

- T1190 Exploit Public-Facing Application
- T1195.002 Supply Chain Compromise: Compromise Software Supply Chain
- T1203 Exploitation for Client Execution
- T1059 Command and Scripting Interpreter
- T1608.001 Stage Capabilities: Upload Malware

## Free detection (Splunk SPL, Microsoft KQL, Sigma)

**OpenCode Server Spawns Global Package Install From Remote Tarball — Exploitation (GHSA-632h-h47v-g4x4)** (`TL-2026-5809-SPL-001`)

Detects the OpenCode process (opencode serve / opencode web) launching npm, pnpm or Bun with a global install whose package specifier is a remote tarball or URL. This is the post-request behaviour of GHSA-632h-h47v-g4x4: a cross-origin text/plain POST to /global/upgrade passes an attacker-chosen 'target' to the package manager, whose preinstall script then runs code. Behaviour-first: it does not depend on the unlogged HTTP request.

- **Languages:** Splunk SPL, Microsoft KQL, Sigma
- **ATT&CK:** T1190, T1195.002, T1203
- **Data sources:** sysmon, windows_process_creation
- **Severity:** high
- **Confidence:** high

### Splunk SPL

````spl
index=sysmon sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=1 earliest=-24h (ParentImage="*opencode*" OR ParentCommandLine="*opencode*") (Image="*npm*" OR Image="*pnpm*" OR Image="*bun.exe" OR Image="*node.exe") (CommandLine="* -g*" OR CommandLine="* --global*" OR CommandLine="* global add*") (CommandLine="*http://*" OR CommandLine="*https://*" OR CommandLine="*.tgz*" OR CommandLine="*git+*" OR CommandLine="*file:*")
| rex field=CommandLine "(?i)(?<target_spec>(?:https?|git[+]\w+|file):[^\s'\x22]+|[^\s'\x22]+[.]tgz)"
```comment: OpenCode (opencode serve/web) spawning a global npm/pnpm/bun install with a remote tarball/URL specifier is the GHSA-632h-h47v-g4x4 exploit chain```
| table _time host user ParentImage ParentCommandLine Image CommandLine target_spec
````

### Microsoft KQL

```kql
DeviceProcessEvents
| where Timestamp > ago(24h)
| where InitiatingProcessFileName has "opencode" or InitiatingProcessCommandLine has "opencode"
| where FileName in~ ("npm", "npm.cmd", "pnpm", "pnpm.cmd", "pnpm.exe", "bun", "bun.exe", "node", "node.exe")
| where ProcessCommandLine has_any (" -g", "--global", "global add")
| where ProcessCommandLine has_any ("http://", "https://", ".tgz", "git+", "file:")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine
| order by Timestamp desc
```

### Sigma

```yaml
title: OpenCode Server Spawns Global Package Install From Remote Tarball
id: 7c1e4a52-3b8d-5e61-9a47-1d2f6b8c0a11
status: experimental
description: Detects the OpenCode process (opencode serve / opencode web) spawning npm, pnpm or Bun with a global install of a remote tarball or URL package specifier, the GHSA-632h-h47v-g4x4 /global/upgrade exploit chain.
references:
    - https://github.com/anomalyco/opencode/security/advisories/GHSA-632h-h47v-g4x4
    - https://securitylabs.datadoghq.com/articles/opencode-upgrade-remote-code-execution/
    - https://mend.io/vulnerability-database/WS-2026-0073/
author: Threadlinqs Team
date: 2026-11-12
tags:
    - attack.initial-access
    - attack.t1190
    - attack.t1195.002
    - attack.execution
    - attack.t1203
logsource:
    category: process_creation
    product: windows
detection:
    selection_parent:
        ParentCommandLine|contains: 'opencode'
    selection_pm:
        CommandLine|contains:
            - 'npm'
            - 'pnpm'
            - 'bun'
    selection_global:
        CommandLine|contains:
            - ' -g'
            - '--global'
            - ' global add'
    selection_remote:
        CommandLine|contains:
            - 'http://'
            - 'https://'
            - '.tgz'
            - 'git+'
            - 'file:'
    condition: selection_parent and selection_pm and selection_global and selection_remote
falsepositives:
    - Legitimate OpenCode self-upgrade from a private npm mirror or internal tarball host
level: high

```

**Known false positives:**

- Legitimate OpenCode upgrade pulling from an internal npm mirror or tarball host
- Developers manually testing OpenCode builds from a tarball URL

**Tuning notes:** Allowlist internal registry/mirror hostnames in target_spec. Windows/Sysmon scope for SPL; Linux/macOS hosts are covered by the KQL form (DeviceProcessEvents) and the Linux lifecycle rule TL-2026-5809-KQL-002. Fixed in OpenCode 1.18.22 (target must be semver).

### 8 more detection rules (Splunk SPL, Microsoft KQL, Sigma), unlock with TL Creds

- Browser Connection To Default OpenCode Local Server ([indicator]:4096) — Drive-by Delivery (locked: unlock with TL Creds)
- Package Manager Global Install Spawns Shell With Download/Reverse-Shell Idioms — Post-Exploitation (Linux/macOS) (locked: unlock with TL Creds)
- Package Manager Global Install Connects To Non-Registry Host — Remote Tarball Fetch / C2 Staging (locked: unlock with TL Creds)
- Non-Semver [indicator] Package Specifier Passed To Package Manager — Exploitation (locked: unlock with TL Creds)
- Inline JavaScript Evaluation In Package Manager Global Install Lifecycle Script — Post-Exploitation (locked: unlock with TL Creds)
- Script Interpreter Resolves Callback/Tunnelling Service — C2 After Package Lifecycle Execution (locked: unlock with TL Creds)
- Package Manager Global Install Lifecycle Script Runs Download/Execution Tradecraft — Post-Exploitation (Windows) (locked: unlock with TL Creds)
- Package Manager Fetches Tarball From Non-Registry Host — Attacker Package Delivery (OpenCode GHSA-632h-h47v-g4x4) (locked: unlock with TL Creds)

Sign up free to unlock the detection rules: https://threadlinqs.com/?modal=signup

## Sample indicators (1 of 6)

Defanged, TLP:CLEAR.

- File hash: `2a36236132b0588eafbe3a16f2d271144f5a1104`

Full set of 6 indicators unlocks with TL Creds: https://threadlinqs.com/tl-creds

## Sources

- [Discovering and exploiting a remote code execution vulnerability in OpenCode (GHSA-632h-h47v-g4x4)](https://securitylabs.datadoghq.com/articles/opencode-upgrade-remote-code-execution/)
- [GHSA-632h-h47v-g4x4: Cross-site OpenCode server upgrade request can install arbitrary packages for npm-based installations](https://github.com/anomalyco/opencode/security/advisories/GHSA-632h-h47v-g4x4)
- [Mend.io Vulnerability Database WS-2026-0073](https://mend.io/vulnerability-database/WS-2026-0073/)
- [OpenCode fix commit referenced by Mend.io](https://github.com/anomalyco/opencode/commit/2a36236132b0588eafbe3a16f2d271144f5a1104)
- [OpenCode PR #44686 (fix)](https://github.com/anomalyco/opencode/pull/44686)
- [OpenCode PR #24853 (introduced the vulnerable upgrade behavior)](https://github.com/anomalyco/opencode/pull/24853)

## Full data

The other 8 detection rules (Splunk SPL / Microsoft KQL / Sigma) unlock with TL Creds; a free account includes daily creds: https://threadlinqs.com/?modal=signup
Indicator values unlock with TL Creds, at a lower price on Red and Purple; AI agents can query rules and IOCs through the Threadlinqs MCP server (Purple): https://intel.threadlinqs.com/mcp

Canonical: https://intel.threadlinqs.com/threat/TL-2026-5809
