feat(post-mcp-verify): E14 part 2 — cumulative-drift MEDIUM advisory [skip-docs]
Wave C step C2: surface the cumulative-drift signal from checkDescriptionDrift() (added in C1) as a separate MEDIUM advisory with finding category mcp-cumulative-drift. Independent of the existing per-update drift advisory — a slow-burn rug-pull that keeps each update below the 10% per-update threshold but cumulatively drifts >=25% from the sticky baseline now triggers the new advisory without ever crossing the per-update bar. The advisory references /security mcp-baseline-reset (added in C3) so the user knows how to acknowledge a legitimate MCP server upgrade. CLAUDE.md updates: - post-mcp-verify hooks-table row mentions per-update + cumulative drift - mcp-description-cache lib bullet documents baseline schema, history, cumulative threshold policy key, and LLM_SECURITY_MCP_CACHE_FILE override. Tests: 2 new hook tests using LLM_SECURITY_MCP_CACHE_FILE for cache isolation. Existing 68 still pass; total 70. Plugin README and root marketplace README updates land in C3 alongside the new /security mcp-baseline-reset slash command (combined Wave-C doc update per plan §"Wave C — Touch" list). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
eaac830300
commit
427b68eca9
3 changed files with 109 additions and 4 deletions
|
|
@ -421,6 +421,11 @@ if (isHtmlSource && outputText.length >= MIN_INJECTION_SCAN_LENGTH) {
|
|||
// =========================================================================
|
||||
// MCP description drift detection (OWASP MCP05 — Rug Pull)
|
||||
// Checks if the MCP tool's description has changed since first seen.
|
||||
// Two signals:
|
||||
// - per-update drift (>10% Levenshtein vs previous)
|
||||
// - cumulative drift (>=25% Levenshtein vs sticky baseline) — catches
|
||||
// slow-burn rug-pulls where each update stays under the per-update
|
||||
// threshold but cumulatively diverges from the original. v7.3.0 / E14.
|
||||
// Only relevant for MCP tools that provide a description in tool_input.
|
||||
// =========================================================================
|
||||
const isMcpTool = toolName?.startsWith('mcp__');
|
||||
|
|
@ -438,6 +443,19 @@ if (isMcpTool && !isTrustedMcp) {
|
|||
` A changed tool description may indicate the MCP server has been compromised.`
|
||||
);
|
||||
}
|
||||
// Cumulative-drift advisory (mcp-cumulative-drift, MEDIUM). Independent
|
||||
// of per-update drift — a slow-burn rug-pull triggers this without
|
||||
// ever crossing the per-update threshold.
|
||||
if (driftResult.cumulative && driftResult.cumulative.drifted) {
|
||||
const baselineDesc = driftResult.cumulative.baseline || '';
|
||||
advisories.push(
|
||||
`MCP tool cumulative description drift — MEDIUM (mcp-cumulative-drift, OWASP MCP05).\n` +
|
||||
` ${driftResult.cumulative.detail}\n` +
|
||||
` Baseline: "${baselineDesc.slice(0, 120)}${baselineDesc.length > 120 ? '...' : ''}"\n` +
|
||||
` Current: "${description.slice(0, 120)}${description.length > 120 ? '...' : ''}"\n` +
|
||||
` Reset the baseline after a legitimate MCP server upgrade with: /security mcp-baseline-reset`
|
||||
);
|
||||
}
|
||||
} catch { /* drift check is advisory, never block */ }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue