mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-24 02:46:51 -06:00
security: authenticate the local control server with a per-session token (CWE-306) (#1844)
* security: authenticate the local control server with a per-session token (CWE-306) The optional `--control PORT` server listens on loopback TCP and dispatched any JSON request without authenticating the peer. Loopback TCP does not distinguish operating-system users, so another local account could connect and drive the desktop user's command and file authority (for example reading files through native Lisp, or create/truncate writes). Authenticate the peer with an unguessable per-session token: - New `cadcraft_mcp::control_token` module: `issue(port)` generates a 256-bit token and writes it to `cadcraft-control-<port>.token` in the per-user runtime directory with owner-only permissions (0600 on Unix; per-user LOCALAPPDATA on Windows). `read(port)` reads it; `matches` compares in constant time. - The control server issues the token at startup and requires every request to carry a matching `token` field; requests without one get an `unauthorized` reply and the connection is closed before dispatch. - The MCP bridge (`Remote`) reads the token from the owner-only file — which needs the desktop user's own filesystem access — and sends it on every request, so the bridge keeps working unchanged for the legitimate user. A different local user cannot read the token and cannot authenticate. Updates `docs/control-protocol.md`. New tests cover token issue/read/compare, file permissions, and that the server refuses unauthenticated requests while accepting authenticated ones. Addresses finding row 48. * fix: recover control authentication across server restarts --------- Co-authored-by: skylartaylor <26588250+skylartaylor@users.noreply.github.com>
This commit is contained in:
co-authored by
skylartaylor
parent
916be26ed3
commit
ca578a8fb7
@@ -5,10 +5,18 @@ Start the desktop app with `--control PORT` (or `CADCRAFT_CONTROL_PORT=PORT`). I
|
||||
`--control` wins over the variable; a bare `--control` keeps the variable's port.
|
||||
|
||||
```json
|
||||
{"id": 1, "method": "cmdline.input", "params": {"text": "circle 0,0 5"}}
|
||||
{"id": 1, "method": "cmdline.input", "params": {"text": "circle 0,0 5"}, "token": "<session token>"}
|
||||
{"id": 1, "ok": true, "result": {"prompt": "Command:", "output": ["Command: CIRCLE"], ...}}
|
||||
```
|
||||
|
||||
Every request must carry the session `token`. Because loopback TCP cannot tell local operating
|
||||
system users apart, the app writes an unguessable per-session token to an owner-only file when the
|
||||
control server starts, and refuses (`unauthorized`) any request without a matching token. The file
|
||||
is `cadcraft-control-<port>.token` in the per-user runtime directory (`$XDG_RUNTIME_DIR`, else
|
||||
`~/.cache`; `%LOCALAPPDATA%` on Windows); its path is logged at startup. A client reads the token
|
||||
from that file — which requires the desktop user's own filesystem access — and includes it on each
|
||||
line. The MCP bridge (`cadcraft-cli mcp --connect`) does this automatically.
|
||||
|
||||
Errors come back as `{"id": …, "ok": false, "error": "message"}`. An unknown method's error points
|
||||
to `control.methods`, which lists the methods the server answers.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user