Skip to content

Security: nubo-db/dynoxide

SECURITY.md

Security Policy

Reporting a vulnerability

If you believe you've found a security issue in dynoxide, please report it privately rather than opening a public issue.

Use GitHub's private vulnerability reporting: https://github.com/nubo-db/dynoxide/security/advisories/new

I aim to acknowledge reports within 5 business days. Fix timelines depend on severity: critical issues affecting the loopback-only boundary, within 30 days; other confirmed issues, best effort, typically within 90 days.

Threat model

dynoxide's MCP HTTP transport is intended for local single-user development, with an explicit opt-in for wider exposure. It is opt-in to begin with: the default dynoxide mcp uses stdio and has no network exposure. Only dynoxide mcp --http (or dynoxide serve --mcp) opens an HTTP listener.

The HTTP transport defends against two threats: direct-from-tooling callers (anyone who can reach the port) and browser-based cross-origin attacks (DNS rebinding, cross-origin CSRF).

dynoxide:

  • Requires a bearer token on every request. Each /mcp request must carry Authorization: Bearer <token>; a missing or wrong token returns an identical 401 (no oracle distinguishes the two). On a loopback bind with no token supplied, dynoxide generates one on first run, persists it to a per-user config file (mode 0600 on Unix; on Windows it lives under your per-user %APPDATA%, which other standard accounts cannot read), and prints client-config guidance. Supply your own with --token / --mcp-token or DYNOXIDE_MCP_AUTH_TOKEN. There is no rotation mechanism: to rotate, delete the persisted file (or change the env var) and restart.
  • Defaults to a loopback bind. --host / --mcp-host can widen it, but a non-loopback bind will not start without an explicit token — auto-generation is loopback-only.
  • Validates the Host header against a loopback allowlist (localhost, 127.0.0.1, ::1); anything else returns 403. --allowed-host / --mcp-allowed-host adds names for non-loopback by-name access. The auth check runs first, so a valid token holder who then spoofs Host still gets 403 — the allowlist is defense-in-depth, not the primary control.
  • Validates the Origin header when present, against http://localhost, http://127.0.0.1, and any added hosts; anything else returns 403. Native MCP clients (Claude Code, Cursor, the dynoxide CLI) don't send an Origin header and pass through unaffected.

With authentication in place, dynoxide is suitable for:

  • Local development on a personal machine
  • CI environments
  • Dockerised and network-exposed deployments, provided a token is set and treated as a secret (passed via DYNOXIDE_MCP_AUTH_TOKEN, not a flag, to keep it out of process listings and shell history)

A loopback-only escape hatch, --no-auth / --mcp-no-auth, disables authentication entirely; it refuses to start on a non-loopback bind. Use it only on a trusted single-user machine where no other local process is a concern.

The stdio transport is unaffected by all of the above — it is process-scoped and has no network surface.

Known advisories

See the Security Advisories tab.

Learn more about advisories related to nubo-db/dynoxide in the GitHub Advisory Database