PenPot MCP REPL server binds to 0.0.0.0 with unauthenticated /execute endpoint — RCE
Date: 2026-05
Affected: npm/@penpot/mcp
Attack vector: rce
Category: vulnerability-disclosure
Severity: High
CVE: CVE-2026-45805
CWE: CWE-749
CVSS: 8.8 (CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

### Summary The MCP module's `ReplServer` binds to all interfaces (`0.0.0.0:4403`) and exposes a `/execute` endpoint that runs arbitrary code with zero authentication. Anyone on the network can POST JavaScript and it runs on the server. The main `PenpotMcpServer` was partially fixed for a similar binding issue (#8683), but `ReplServer.ts` was missed. ### Details `mcp/packages/server/src/ReplServer.ts:89`: ```typescript this.server = this.app.listen(this.port, () => { // NO HOST ARGUMENT — Express defaults to 0.0.0.0 ``` Compare with `PenpotMcpServer.ts:301` which correctly binds to `this.host` (default `"localhost"`): ```typescript this.app.listen(this.port, this.host, async () => { ``` The `/execute` endpoint at `ReplServer.ts:52-79`: ```typescript this.app.post("/execute", async (req, res) => { const { code } = req.body; // No auth check. Executes code via PluginBridge.executePluginTask() const task = new ExecuteCodePluginTask({ code }); const result = await this.pluginBridge.executePluginTask(task); ``` No auth middleware, no token check, no nothing. POST JSON with a `code` field and it runs. This was partially flagged in #8683 (March 2026), which noted that `PenpotMcpServer.ts` was binding to `0.0.0.0`. PR #8686 attempted a fix but was closed without merging, and it only touched `PenpotMcpServer.ts` and `vite.config.ts` — `ReplServer.ts` wasn't in the diff. On current develop, `ReplServer.ts` line 89 still calls `listen(this.port)` with no ho


Mitigations:

Architectural layers (MAESTRO):