From 770af247e95273b2c26d8bf7c66b9bb4db53e4dd Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 25 May 2026 23:51:16 +0000 Subject: [PATCH] security: harden dashboard server and CI pipeline - dashboard.ts: add Content-Security-Policy, X-Content-Type-Options, X-Frame-Options headers to every response - dashboard.ts: fix DNS-rebinding guard to fail-closed (empty/absent Host header was previously allowed through) - dashboard.ts: cap concurrent SSE /clock connections at 8 to prevent unbounded timer accumulation - dashboard.ts: enforce application/json Content-Type on /cmd POST - dashboard.ts: log server errors to stderr instead of silently dropping - track.ts: escape param string before constructing RegExp in applyParam to prevent regex injection / ReDoS from untrusted POST bodies - ci.yml: pin actions/checkout and actions/setup-node to full commit SHAs to protect against mutable tag supply-chain attacks https://claude.ai/code/session_011GALMvXr1b8uKfPy17fxxK --- .github/workflows/ci.yml | 4 ++-- mcp/src/dashboard.ts | 37 +++++++++++++++++++++++++++++++++---- mcp/src/track.ts | 3 ++- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81dbd6e..5b63d16 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,8 +12,8 @@ jobs: run: working-directory: mcp steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: 20 cache: npm diff --git a/mcp/src/dashboard.ts b/mcp/src/dashboard.ts index 9f1dfe0..4bdd699 100644 --- a/mcp/src/dashboard.ts +++ b/mcp/src/dashboard.ts @@ -7,6 +7,19 @@ type CmdHandler = (body: CmdBody) => Promise | string; // Local dashboard: serves the HTML (read fresh per request so UI edits don't need // an MCP reload), exposes /state (JSON) and /cmd (POST control commands). +// Cap concurrent SSE /clock connections to prevent unbounded timer accumulation. +const SSE_MAX = 8; +let sseCount = 0; + +// Security headers applied to every response (including 403s). +const SEC_HEADERS: Record = { + "x-content-type-options": "nosniff", + "x-frame-options": "DENY", + // Scripts are all src-loaded (no inline scripts); styles use 'unsafe-inline' for the