GHSA-79wm-x847-7cvg: OS Command Injection

Published Sep 3, 2026
·
Updated

Summary npx claude-code-templates --studio launches "Claude Code Studio", an Express HTTP server (cli-tool/src/sandbox-server.js, default port 3444) that binds to all interfaces (0.0.0.0), sets Access-Control-Allow-Origin: , and requires no authentication. Two POST endpoints pass attacker-controlled request-body fields into childprocess.spawn(..., { shell: true }). Because shell: true makes Node join the argv array into a single sh -c string, the fields are parsed by the shell and metacharacters execute. Any unauthenticated attacker who can reach the port — a malicious web page the developer visits, or anyone on the same LAN — can execute arbitrary OS commands on the developer's machine.

Details In cli-tool/src/sandbox-server.js:

- app.listen(PORT, ...) is called with no host argument, so the server listens on 0.0.0.0 / :: (reachable from the LAN, not just localhost). - The CORS middleware sends Access-Control-Allow-Origin: and answers the preflight OPTIONS for any origin, so a browser will deliver cross-origin POSTs to it. - There is no authentication on any endpoint.

The vulnerable sinks:

1. POST /api/execute — the prompt body field flows into executeLocalTask(): js const child = spawn('claude', [finalPrompt], { / ... / shell: true }); The only validation on prompt is a length check (>= 10 chars). With shell: true, finalPrompt is interpreted by the shell.

2. POST /api/install-agent — the agentName body field: const child = spawn('npx', ['claude-code-templates@latest', '--agent', agentName, '--yes'], { / ... / shell: true }); 2. agentName is used unvalidated. (The same unsafe pattern is also reachable through /api/execute's agent field via checkAndInstallAgent().)

Root cause: spawn(cmd, argsArray, { shell: true }) does not keep argsArray as separate argv entries — Node builds cmd + ' ' + argsArray.join(' ') and runs it via sh -c, so every element is subject to shell parsing.

PoC

Victim npx claude-code-templates --studio # server on 0.0.0.0:3444

Attacker (another LAN host, or a malicious web page fetch(), or locally) curl -s -X POST http://127.0.0.1:3444/api/execute \ -H 'Content-Type: application/json' \ --data '{"prompt":"aaaaaaaaaa; touch /tmp/CCTRCEPROOF","mode":"local"}'

curl -s -X POST http://127.0.0.1:3444/api/install-agent \ -H 'Content-Type: application/json' \ --data '{"agentName":"x; touch /tmp/CCTAGENTPROOF #"}'

ls -la /tmp/CCTRCEPROOF /tmp/CCTAGENTPROOF # both created => injected commands ran The aaaaaaaaaa padding satisfies the 10-char minimum, then ; (or $(...), or backticks) starts the injected command. claude/npx do not even need to be installed — the injected segment runs regardless.

Confirmed at runtime on v1.28.13 (Node 22, Linux): both marker files were created, the server listened on :3444, and an OPTIONS preflight from Origin: https://evil.example returned 200 with Access-Control-Allow-Origin: .

Impact

Unauthenticated remote code execution (CWE-78) on any machine running --studio. Two reachability paths: - Drive-by: a developer running --studio who visits an attacker-controlled web page — the page's cross-origin fetch() (Content-Type application/json) passes the wildcard CORS preflight and delivers the POST, achieving RCE with no other interaction. - LAN: because the server binds 0.0.0.0, anyone on the same network (office, co-working space, public Wi-Fi) can hit port 3444 directly.

Impact is full compromise of the developer's user account (arbitrary command execution with the developer's privileges): source code, SSH keys, cloud credentials, and .env secrets.

Suggested fix

- Remove shell: true from all three spawns so arguments stay discrete argv entries (kills the injection). - Validate agentName against a strict allowlist (^[A-Za-z0-9./-]+$). - Bind to loopback only (app.listen(PORT, '127.0.0.1', ...)). - Replace the wildcard CORS with a same-origin allowlist and reject other origins.

Affected Software

1 affected componentFixes available
npm/claude-code-templates<=1.29.2
1.29.4

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/claude-code-templates to a version that resolves this vulnerability.

    Fixed in 1.29.4

Event History

Sep 3, 2026
Advisory Published
via GitHub·07:50 PM
Data Sourced
via GitHub·07:50 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Who can realistically exploit this issue?

Any unauthenticated party that can reach the Studio server's port can exploit it, including someone on the same LAN. A malicious website visited by the developer can also send cross-origin POST requests because the server permits all origins.

2

What must be running for an attacker to exploit it?

Claude Code Studio must be launched through `npx claude-code-templates --studio`, which starts the Express server on its default port, 3444. The server binds to all interfaces rather than only localhost and exposes unauthenticated POST endpoints.

3

What level of access does an attacker need?

The attacker does not need credentials or prior access to the developer's machine. They need network reachability to the server, or they can induce the developer's browser to send requests from a malicious web page.

4

What is the impact of successful exploitation?

Attacker-controlled request fields reach `child_process.spawn` with `shell: true`, allowing shell metacharacters to be interpreted. Successful exploitation can execute arbitrary operating-system commands on the developer's machine.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203