Skip to content

fix UI redressing vulnerability#2695

Open
0xcucumbersalad wants to merge 2 commits intodecocms:mainfrom
0xcucumbersalad:fix/ui-reddressing
Open

fix UI redressing vulnerability#2695
0xcucumbersalad wants to merge 2 commits intodecocms:mainfrom
0xcucumbersalad:fix/ui-reddressing

Conversation

@0xcucumbersalad
Copy link
Contributor

@0xcucumbersalad 0xcucumbersalad commented Mar 13, 2026

What is this contribution about?

This PR mitigates UI redressing (clickjacking) attacks against the MCP Mesh admin interface by adding X-Frame-Options: DENY and Content-Security-Policy: frame-ancestors 'none' security headers across all response paths.

Without these headers, an attacker could embed the Mesh admin UI inside a malicious page using an <iframe>, tricking authenticated users into performing unintended actions (e.g., modifying workspace settings, managing MCP servers, or changing access controls) by overlaying invisible frames on top of deceptive UI elements.

The fix applies headers at three layers to ensure full coverage:

  • Hono middleware (apps/mesh/src/api/app.ts) — covers all API and server-rendered responses
  • Bun.serve fetch handler (apps/mesh/src/index.ts) — wraps static asset responses that bypass Hono's middleware pipeline via handleAssets
  • Asset server (packages/runtime/src/asset-server/index.ts) — adds headers directly to index.html cache-control responses so the entrypoint HTML is always protected

How to Test

  1. Start the Mesh locally with bun run dev
  2. Open browser DevTools → Network tab, load http://localhost:3000
  3. Verify that responses (HTML page, API calls) include both X-Frame-Options: DENY and Content-Security-Policy: frame-ancestors 'none'
  4. Create a test HTML file that attempts to embed the Mesh UI in an iframe: <iframe src="http://localhost:3000"></iframe> — the browser should refuse to render it
  5. Confirm the application functions normally (no broken pages or blocked resources)

Summary by cubic

Mitigates UI redressing (clickjacking) in the Mesh admin by sending deny‑framing headers on all responses. Blocks iframe embedding to protect authenticated actions.

  • Bug Fixes
    • Add X-Frame-Options: DENY and Content-Security-Policy: frame-ancestors 'none' via Hono middleware for API and server-rendered responses.
    • Wrap static asset responses from handleAssets with the same headers in apps/mesh/src/index.ts.

Written for commit c94d214. Summary will update on new commits.

@github-actions
Copy link
Contributor

🧪 Benchmark

Should we run the Virtual MCP strategy benchmark for this PR?

React with 👍 to run the benchmark.

Reaction Action
👍 Run quick benchmark (10 & 128 tools)

Benchmark will run on the next push after you react.

@github-actions
Copy link
Contributor

Release Options

Should a new version be published when this PR is merged?

React with an emoji to vote on the release type:

Reaction Type Next Version
👍 Prerelease 2.165.2-alpha.1
🎉 Patch 2.165.2
❤️ Minor 2.166.0
🚀 Major 3.0.0

Current version: 2.165.1

Deployment

  • Deploy to production (triggers ArgoCD sync after Docker image is published)

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 3 files

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/runtime/src/asset-server/index.ts">

<violation number="1">
P1: Shared asset server stopped sending anti-clickjacking headers on HTML responses, weakening default protection for `createAssetHandler()` consumers.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@@ -10,6 +10,7 @@ import { resolve, dirname, join, extname, basename, sep } from "path";
* hash in the filename changes on every build.
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Shared asset server stopped sending anti-clickjacking headers on HTML responses, weakening default protection for createAssetHandler() consumers.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/runtime/src/asset-server/index.ts, line 19:

<comment>Shared asset server stopped sending anti-clickjacking headers on HTML responses, weakening default protection for `createAssetHandler()` consumers.</comment>

<file context>
@@ -10,17 +10,13 @@ import { resolve, dirname, join, extname, basename, sep } from "path";
 ): Record<string, string> {
   if (filePath === indexPath || basename(filePath) === "index.html") {
-    return { "Cache-Control": "no-cache", ...SECURITY_HEADERS };
+    return { "Cache-Control": "no-cache" };
   }
 
</file context>
Fix with Cubic

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