Skip to content

fix(mcp): security hardening#54

Merged
karim-semmoud merged 3 commits into
mainfrom
fix/mcp-security-hardening
Jun 2, 2026
Merged

fix(mcp): security hardening#54
karim-semmoud merged 3 commits into
mainfrom
fix/mcp-security-hardening

Conversation

@karim-semmoud
Copy link
Copy Markdown
Member

Summary

Re-aligns Corex MCP with the upstream Tidewave security model (tidewave v0.5.6) and fixes Corex-specific regressions. Corex MCP stays read-only (component discovery only); no Tidewave eval/SQL/log tools are added.

  • Removes global CSP / X-Frame-Options rewriting on non-MCP routes (Corex has no embedded browser client, unlike Tidewave)
  • Initializes MCP tools once at plug boot instead of on every POST
  • Returns repo-relative source_path via Corex.MCP.root/0 instead of absolute filesystem paths
  • Tightens tool argument validation (fail closed on invalid input)
  • Trims /corex/config JSON to reduce fingerprinting
  • Adds a production guard: plug Corex.MCP raises in :prod unless force: true

Motivation

Corex MCP is forked from Dashbit's Tidewave MCP transport. A security review found several divergences from upstream and unnecessary behavior inherited without Tidewave's embedded client use case. This PR brings Corex in line with Tidewave where appropriate and hardens areas specific to Corex (path disclosure, tool validation, prod mounting).

Changes

Plug (lib/mcp/plug.ex)

  • Removed register_before_send CSP rewrite and X-Frame-Options deletion on all non-/corex responses
  • Added Corex.MCP.root/0 for project-root resolution (config :corex, mcp_root: ...)
  • Calls Server.init_tools/0 once in init/1
  • Runs validate!/1 on every request (Tidewave parity)
  • Raises at init in :prod unless force: true is passed

Server (lib/mcp/server.ex)

  • Removed per-request init_tools/0 from handle_http_message/1
  • Dropped :public from the ETS table (matches upstream)
  • Documented upstream sync point: tidewave v0.5.6

Component docs (lib/mcp/component_docs.ex)

  • source_path is now relative to Corex.MCP.root/0
  • Paths outside the project root fall back to basename only

Router (lib/mcp/router.ex)

  • /corex/config no longer exposes allow_remote_access

Tools

  • list_components: rejects non-empty argument maps
  • get_component: requires exactly id (string, max 64 bytes); unknown keys rejected
  • installation_guide: invalid or unknown scenario / extra keys return {:error, :invalid_arguments}

Docs (guides/MCP.md)

  • Added Security, Configuration, and CSP sections
  • Documented upstream alignment and mcp_root / force options

Intentionally unchanged (Tidewave parity)

  • Loopback IP gate and allow_remote_access: false default
  • Origin header blocking on /corex/mcp and /corex/config
  • Stack traces in tool error responses (MCP spec)
  • Read-only tool set (no project_eval, SQL, logs, etc.)

Test plan

  • mix test test/corex/mcp (53 tests)
  • mix lint
  • mix test e2e/test/e2e_web/corex_mcp_test.exs
  • Manual: Cursor connects to http://localhost:4000/corex/mcp; list_components and get_component work
  • Manual: app pages keep original CSP and X-Frame-Options when plug Corex.MCP is mounted

@karim-semmoud karim-semmoud self-assigned this Jun 2, 2026
@karim-semmoud karim-semmoud mentioned this pull request Jun 2, 2026
8 tasks
@karim-semmoud karim-semmoud merged commit 801c2f2 into main Jun 2, 2026
14 checks passed
@karim-semmoud karim-semmoud deleted the fix/mcp-security-hardening branch June 2, 2026 05:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant