llm-trust-guard 4.19.0 → 4.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/README.md +19 -0
- package/dist/guards/mcp-security-guard.d.ts +37 -1
- package/dist/guards/mcp-security-guard.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,50 @@ All notable changes to `llm-trust-guard` will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [4.20.0] - 2026-04-24
|
|
9
|
+
|
|
10
|
+
### Added — MCP Sampling Attack Detection (Unit42 + Blueinfy, Feb 2026)
|
|
11
|
+
|
|
12
|
+
`MCPSecurityGuard` now validates MCP sampling responses via `validateSamplingResponse()`, closing the only previously unaddressed MCP attack surface.
|
|
13
|
+
|
|
14
|
+
Three attack vectors detected (tied to published Unit42 + Blueinfy Feb 2026 research):
|
|
15
|
+
|
|
16
|
+
- **Resource drain** (`sd_call_again`, `sd_loop_until`, `sd_do_not_stop`, `sd_n_times`, `sd_exhaust_resources`): Hidden instructions embedded in sampling response bodies that cause the agent to loop indefinitely, repeat tool calls N times, or exhaust token quotas — degrading or DoS-ing the agent runtime
|
|
17
|
+
- **Conversation hijacking** (`sd_fake_user_turn`, `sd_fake_assistant_turn`, `sd_role_json`, `sd_system_xml`, `sd_from_now_on`, `sd_new_instructions`, `sd_ignore_previous`): Injected fake user/assistant turns, JSON role fields (`"role": "system"`), XML role tags, and system-prompt override phrases that redirect agent behavior within the sampling response
|
|
18
|
+
- **Covert tool invocation** (`sd_anthropic_tool_xml`, `sd_tool_result_xml`, `sd_openai_tool_call`, `sd_bracket_tool_call`, `sd_double_brace_call`, `sd_invoke_name_attr`): Tool-call syntax embedded in plain-text responses (Anthropic `<function_calls>`, OpenAI `"tool_calls": [...]`, bracket notation `[TOOL:...]`) that cause the agent to invoke tools without user awareness
|
|
19
|
+
|
|
20
|
+
New export: `MCPSamplingResponse` interface.
|
|
21
|
+
|
|
22
|
+
Server reputation degrades automatically on any sampling attack detection.
|
|
23
|
+
|
|
24
|
+
### Tests
|
|
25
|
+
|
|
26
|
+
- +6 `MCPSecurityGuard` sampling tests (resource drain, conversation hijack ×2, covert tool invocation, reputation degradation, clean FP)
|
|
27
|
+
- **All 711 tests pass** (was 705), zero regressions
|
|
28
|
+
|
|
29
|
+
### Stats
|
|
30
|
+
- 34 guards, 711 tests, zero dependencies
|
|
31
|
+
|
|
32
|
+
## [4.19.1] - 2026-04-23
|
|
33
|
+
|
|
34
|
+
### Added — Measured Performance
|
|
35
|
+
|
|
36
|
+
- Published held-out benchmark results in [tests/adversarial/RESULTS-v4.19.0.md](tests/adversarial/RESULTS-v4.19.0.md). Methodology, 95% Wilson CIs, hand-adjudicated label noise, and reproducibility scripts
|
|
37
|
+
- New README section "Measured Performance" summarizing the findings:
|
|
38
|
+
- On Giskard (n=35) and Compass CTF Chinese (n=11), Pipeline A detection rate is unchanged from v4.13.5 (80.00%, 9.09%). Underpowered — "no evidence of improvement," not "proof of no improvement"
|
|
39
|
+
- On WildChat-1M (10,000 real ChatGPT production prompts, seed=42), Pipeline A corrected FPR is ~2.73% [95% CI 2.43, 2.84] after canonical-marker + 50-sample hand-adjudication (203 canonical TPs + ~17 extrapolated TPs among unmarked → ~220 true jailbreak attempts in the 493 blocks)
|
|
40
|
+
- Same order of magnitude as Meta Prompt Guard 86M's self-reported 3–5% OOD FPR; not a head-to-head comparison
|
|
41
|
+
- New reproducibility scripts: `tests/adversarial/extract_wildchat.py`, `classify_wildchat_blocks.py`, `wildchat-fpr.ts`, `wildchat-block-dump.ts`, `v419-delta-benchmark.ts`, `hand-labels.json`, and `tests/adversarial/README.md`
|
|
42
|
+
|
|
43
|
+
### Not changed
|
|
44
|
+
|
|
45
|
+
- No code changes to any guard. No detection patterns added or modified. No published API changed.
|
|
46
|
+
- All 705 tests still pass
|
|
47
|
+
|
|
48
|
+
### Context
|
|
49
|
+
|
|
50
|
+
- [ARTICLE-2-REGEX-CEILING.md](https://github.com/nkratk/llm-trust-guard/blob/main/../ARTICLE-2-REGEX-CEILING.md) now includes a 2026-04-23 addendum reconciling v4.13.5 → v4.19.0
|
|
51
|
+
|
|
8
52
|
## [4.19.0] - 2026-04-23
|
|
9
53
|
|
|
10
54
|
### Added — Indirect Injection Expansion
|
package/README.md
CHANGED
|
@@ -222,6 +222,25 @@ const output = guard.filterOutput(llmResponse, session.role);
|
|
|
222
222
|
| ASI09: Trust Exploitation | TrustExploitationGuard | Strong |
|
|
223
223
|
| ASI10: Rogue Agents | DriftDetector, AutonomyEscalationGuard | Moderate |
|
|
224
224
|
|
|
225
|
+
## Measured Performance
|
|
226
|
+
|
|
227
|
+
v4.19.0 benchmark, 2026-04-23. Full methodology, 95% confidence intervals, hand-adjudication labels, and reproducibility scripts: [tests/adversarial/RESULTS-v4.19.0.md](tests/adversarial/RESULTS-v4.19.0.md).
|
|
228
|
+
|
|
229
|
+
**Attack detection on prior-published corpora** (Giskard n=35, Compass CTF Chinese n=11): detection rate has not moved from v4.13.5 → v4.19.0 on the Sanitizer+Encoder pipeline — 80.00% and 9.09% respectively, identical to the v4.13.5 numbers. Six releases of pattern additions (v4.14–v4.19) targeted different attack classes (indirect injection, tool-result validation, memory persistence, multi-agent trust) that these direct-text jailbreak corpora do not exercise. Small sample sizes mean "no evidence of improvement," not "proof of no improvement."
|
|
230
|
+
|
|
231
|
+
**False-positive rate on real ChatGPT production traffic** (WildChat-1M shard 0, 10,000 non-toxic multilingual first-user-turns, seed=42):
|
|
232
|
+
|
|
233
|
+
| Pipeline | Blocks | Raw block rate | Corrected FPR (after label adjudication) |
|
|
234
|
+
|---|---|---|---|
|
|
235
|
+
| Sanitizer + Encoder | 493 / 10,000 | 4.93% [4.52, 5.37] | **~2.73%** [2.43, 2.84] |
|
|
236
|
+
| Detection-only facade | 898 / 10,000 | 8.98% [8.44, 9.56] | ≤6.69% (upper bound; not fully adjudicated) |
|
|
237
|
+
|
|
238
|
+
WildChat filters toxic content but not prompt-injection intent. Canonical-marker analysis + a 50-sample hand-adjudication found that approximately 220 of the 493 Pipeline A blocks are actual jailbreak attempts users sent to ChatGPT, not genuine false positives. Corrected FPR is in the same order of magnitude as Meta Prompt Guard 86M's self-reported 3–5% out-of-distribution FPR — not a head-to-head comparison, but a useful reference point.
|
|
239
|
+
|
|
240
|
+
**Not measured:** detection rate on the four attack classes added in v4.19.0 (CSS-hidden content, HTML attribute directives, JSON agent-directive fields, Reprompt-class markdown exfiltration). No public held-out corpus exists for these at statistical scale. Unit-test coverage is in the v4.19.0 test suite; independent third-party evaluation is invited.
|
|
241
|
+
|
|
242
|
+
For higher detection on adversarial corpora, plug in an ML classifier via the [DetectionClassifier interface](#pluggable-detection).
|
|
243
|
+
|
|
225
244
|
## Defense In Depth
|
|
226
245
|
|
|
227
246
|
This package is one layer. For production systems, combine with:
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* MCPSecurityGuard (L16)
|
|
3
3
|
*
|
|
4
4
|
* Secures Model Context Protocol (MCP) tool integrations.
|
|
5
|
-
* Prevents tool shadowing, server impersonation,
|
|
5
|
+
* Prevents tool shadowing, server impersonation, supply chain attacks,
|
|
6
|
+
* and MCP Sampling channel attacks.
|
|
6
7
|
*
|
|
7
8
|
* Threat Model:
|
|
8
9
|
* - ASI04: Agentic Supply Chain Vulnerabilities
|
|
@@ -10,6 +11,15 @@
|
|
|
10
11
|
* - CVE-2025-6514: mcp-remote command injection
|
|
11
12
|
* - CVE-2025-32711: EchoLeak - silent data exfiltration
|
|
12
13
|
* - Tool Shadowing: Malicious MCP servers impersonating legitimate tools
|
|
14
|
+
* - MCP Sampling Attacks (Unit42 + Blueinfy, Feb 2026): Three concrete vectors
|
|
15
|
+
* delivered through the MCP sampling response channel:
|
|
16
|
+
* (1) Resource drain — hidden prompt appends that trigger infinite tool loops
|
|
17
|
+
* or token exhaustion to degrade or DoS the agent runtime
|
|
18
|
+
* (2) Conversation hijacking — injecting fake user/assistant turns or system
|
|
19
|
+
* prompt overrides into the sampling response body to redirect agent behavior
|
|
20
|
+
* (3) Covert tool invocation — embedding tool-call syntax (Anthropic XML,
|
|
21
|
+
* OpenAI JSON, bracket notation) in plain-text sampling responses to cause
|
|
22
|
+
* the agent to invoke tools without user awareness
|
|
13
23
|
*
|
|
14
24
|
* Protection Capabilities:
|
|
15
25
|
* - MCP server identity verification (signature-based)
|
|
@@ -19,6 +29,7 @@
|
|
|
19
29
|
* - Tool shadowing detection
|
|
20
30
|
* - Server reputation scoring
|
|
21
31
|
* - Command injection prevention
|
|
32
|
+
* - Sampling response scanning (resource drain, conversation hijack, covert tool calls)
|
|
22
33
|
*
|
|
23
34
|
* Upstream SDK advisory — cannot be mitigated at the detection layer:
|
|
24
35
|
* - CVE-2026-25536 (@modelcontextprotocol/sdk 1.10.0–1.25.3, CVSS 7.1):
|
|
@@ -119,6 +130,17 @@ export interface MCPToolCall {
|
|
|
119
130
|
agentId?: string;
|
|
120
131
|
};
|
|
121
132
|
}
|
|
133
|
+
/** Represents a response received from an MCP server via the sampling channel. */
|
|
134
|
+
export interface MCPSamplingResponse {
|
|
135
|
+
/** Text content returned by the MCP server */
|
|
136
|
+
content: string;
|
|
137
|
+
/** Server that produced this sampling response */
|
|
138
|
+
serverId: string;
|
|
139
|
+
/** Agent or tool that initiated the sampling request */
|
|
140
|
+
requestedBy?: string;
|
|
141
|
+
/** Conversation/session ID for audit trail */
|
|
142
|
+
conversationId?: string;
|
|
143
|
+
}
|
|
122
144
|
export interface MCPSecurityResult {
|
|
123
145
|
allowed: boolean;
|
|
124
146
|
reason: string;
|
|
@@ -138,6 +160,12 @@ export interface MCPSecurityResult {
|
|
|
138
160
|
injection_detected: boolean;
|
|
139
161
|
risk_level: string;
|
|
140
162
|
};
|
|
163
|
+
sampling_analysis?: {
|
|
164
|
+
resource_drain_detected: boolean;
|
|
165
|
+
conversation_hijack_detected: boolean;
|
|
166
|
+
covert_tool_invocation_detected: boolean;
|
|
167
|
+
pattern_matches: string[];
|
|
168
|
+
};
|
|
141
169
|
recommendations: string[];
|
|
142
170
|
}
|
|
143
171
|
export declare class MCPSecurityGuard {
|
|
@@ -148,6 +176,7 @@ export declare class MCPSecurityGuard {
|
|
|
148
176
|
private toolToServer;
|
|
149
177
|
private serverViolations;
|
|
150
178
|
private toolDefinitionHashes;
|
|
179
|
+
private readonly SAMPLING_ATTACK_PATTERNS;
|
|
151
180
|
private readonly COMMAND_INJECTION_PATTERNS;
|
|
152
181
|
private readonly SHADOWING_INDICATORS;
|
|
153
182
|
private readonly MALICIOUS_SERVER_PATTERNS;
|
|
@@ -160,6 +189,13 @@ export declare class MCPSecurityGuard {
|
|
|
160
189
|
* Validate MCP tool call
|
|
161
190
|
*/
|
|
162
191
|
validateToolCall(toolCall: MCPToolCall, requestId?: string): MCPSecurityResult;
|
|
192
|
+
/**
|
|
193
|
+
* Validate an MCP sampling response for attack patterns.
|
|
194
|
+
*
|
|
195
|
+
* Covers the three Unit42/Blueinfy (Feb 2026) sampling attack vectors:
|
|
196
|
+
* resource drain, conversation hijacking, and covert tool invocation.
|
|
197
|
+
*/
|
|
198
|
+
validateSamplingResponse(response: MCPSamplingResponse, requestId?: string): MCPSecurityResult;
|
|
163
199
|
/**
|
|
164
200
|
* Register a trusted MCP server
|
|
165
201
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var __createBinding=this&&this.__createBinding||(Object.create?(function(u,e,i,s){s===void 0&&(s=i);var t=Object.getOwnPropertyDescriptor(e,i);(!t||("get"in t?!e.__esModule:t.writable||t.configurable))&&(t={enumerable:!0,get:function(){return e[i]}}),Object.defineProperty(u,s,t)}):(function(u,e,i,s){s===void 0&&(s=i),u[s]=e[i]})),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?(function(u,e){Object.defineProperty(u,"default",{enumerable:!0,value:e})}):function(u,e){u.default=e}),__importStar=this&&this.__importStar||(function(){var u=function(e){return u=Object.getOwnPropertyNames||function(i){var s=[];for(var t in i)Object.prototype.hasOwnProperty.call(i,t)&&(s[s.length]=t);return s},u(e)};return function(e){if(e&&e.__esModule)return e;var i={};if(e!=null)for(var s=u(e),t=0;t<s.length;t++)s[t]!=="default"&&__createBinding(i,e,s[t]);return __setModuleDefault(i,e),i}})();Object.defineProperty(exports,"__esModule",{value:!0}),exports.MCPSecurityGuard=void 0;const crypto=__importStar(require("crypto"));class MCPSecurityGuard{constructor(e={}){this.registeredServers=new Map,this.registeredTools=new Map,this.serverReputation=new Map,this.toolToServer=new Map,this.serverViolations=new Map,this.toolDefinitionHashes=new Map,this.COMMAND_INJECTION_PATTERNS=[{name:"shell_injection",pattern:/[;&|`$]|\$\(|\)\s*[;&|]|`[^`]+`/g,severity:50},{name:"command_substitution",pattern:/\$\{[^}]+\}|\$\([^)]+\)/g,severity:50},{name:"pipe_injection",pattern:/\|\s*(cat|rm|curl|wget|nc|bash|sh|exec)/i,severity:55},{name:"path_traversal",pattern:/\.\.[\/\\]|\.\.%2[fF]/g,severity:45},{name:"absolute_path",pattern:/^\/(?:etc|usr|var|tmp|bin|root)/i,severity:40},{name:"oauth_injection",pattern:/authorization_endpoint.*[;&|`$]/i,severity:55},{name:"redirect_manipulation",pattern:/redirect_uri.*[^\w\-_.~:/?#[\]@!$&'()*+,;=%]/i,severity:45},{name:"applescript_injection",pattern:/osascript|do\s+shell\s+script|tell\s+application/i,severity:55},{name:"git_injection",pattern:/--upload-pack|--receive-pack|-c\s+core\./i,severity:50},{name:"git_url_injection",pattern:/ext::|file:\/\/|ssh:\/\/.*@/i,severity:45},{name:"argument_injection",pattern:/\s--[a-z]+=.*[;&|`$]/i,severity:45},{name:"env_injection",pattern:/\bLD_PRELOAD\b|\bPATH\s*=/i,severity:50}],this.SHADOWING_INDICATORS=[{legitimate:"file_reader",suspicious:/file[-_]?read(er)?s?|read[-_]?files?/i},{legitimate:"database_query",suspicious:/db[-_]?query|sql[-_]?query|query[-_]?db/i},{legitimate:"email_sender",suspicious:/send[-_]?emails?|email[-_]?send(er)?/i},{legitimate:"api_caller",suspicious:/call[-_]?api|api[-_]?call(er)?/i},{legitimate:"code_executor",suspicious:/exec[-_]?code|run[-_]?code|code[-_]?run/i}],this.MALICIOUS_SERVER_PATTERNS=[/postmark-mcp.*fake/i,/unofficial/i,/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/,/pastebin|gist\.github/i,/temp|tmp|test.*mcp/i],this.config={requireServerSignature:e.requireServerSignature??!1,trustedServers:e.trustedServers??[],blockedServers:e.blockedServers??[],allowDynamicRegistration:e.allowDynamicRegistration??!0,toolAllowlist:e.toolAllowlist??[],toolBlocklist:e.toolBlocklist??[],validateOAuthEndpoints:e.validateOAuthEndpoints??!0,allowedOAuthDomains:e.allowedOAuthDomains??[],detectToolShadowing:e.detectToolShadowing??!0,minServerReputation:e.minServerReputation??30,strictMode:e.strictMode??!1,customInjectionPatterns:e.customInjectionPatterns??[]};for(const i of this.config.trustedServers)this.registeredServers.set(i.serverId,{...i,registeredAt:Date.now(),reputationScore:i.reputationScore??90}),this.serverReputation.set(i.serverId,i.reputationScore??90)}validateServerRegistration(e,i){const s=i||`mcp-reg-${Date.now()}`,t=[];let o=!1,r=!1,a=!1,h=!0,n=50;const{server:l,tools:d,oauth:f,signature:g,timestamp:_}=e;this.isServerBlocked(l.serverId,l.name)&&(t.push("server_blocked"),n=0);const v=this.checkMaliciousPatterns(l);if(v.suspicious&&(t.push(...v.violations),n-=30),this.config.requireServerSignature?!g||!l.publicKey?t.push("missing_server_signature"):(r=this.verifyServerSignature(l,g),r?(o=!0,n+=20):(t.push("invalid_server_signature"),n-=40)):o=!0,this.config.detectToolShadowing){const c=this.detectToolShadowing(d,l.serverId);c.detected&&(a=!0,t.push(...c.violations),n-=50)}for(const c of d)this.config.toolAllowlist.length>0&&!this.config.toolAllowlist.includes(c.name)&&(t.push(`tool_not_in_allowlist: ${c.name}`),h=!1),this.config.toolBlocklist.includes(c.name)&&(t.push(`tool_blocked: ${c.name}`),h=!1),this.detectInjection(c.description).detected&&(t.push(`injection_in_tool_description: ${c.name}`),n-=20);if(f&&this.config.validateOAuthEndpoints){const c=this.validateOAuthConfig(f);c.valid||(t.push(...c.violations),n-=30)}const m=Date.now()-_;m<0?t.push("future_timestamp"):m>300*1e3&&t.push("stale_registration"),!this.config.allowDynamicRegistration&&!this.isTrustedServer(l.serverId)&&t.push("dynamic_registration_disabled"),n=Math.max(0,Math.min(100,n));const p=n<this.config.minServerReputation||this.config.strictMode&&t.length>0||a;return p||this.registerServer(l,d,n),{allowed:!p,reason:p?`Server registration blocked: ${t.slice(0,3).join(", ")}`:"Server registration validated",violations:t,request_id:s,server_analysis:{server_verified:o,signature_valid:r,reputation_score:n,is_shadowing:a,tools_allowed:h},recommendations:this.generateRecommendations(t,"registration")}}validateToolCall(e,i){const s=i||`mcp-call-${Date.now()}`,t=[];let o=!1,r=!0,a=!0,h=!1,n="low";const{toolName:l,serverId:d,parameters:f}=e,g=this.registeredTools.get(l);if(g){o=!0,n=g.riskLevel||"low";const p=this.toolToServer.get(l);p&&p!==d&&(t.push("server_tool_mismatch"),h=!0)}else t.push("tool_not_registered");const _=this.serverReputation.get(d)??0;_<this.config.minServerReputation&&t.push("low_server_reputation"),this.config.toolAllowlist.length>0&&!this.config.toolAllowlist.includes(l)&&(t.push("tool_not_in_allowlist"),r=!1),this.config.toolBlocklist.includes(l)&&(t.push("tool_blocked"),r=!1);const v=this.scanParameters(f);if(v.injectionDetected&&(h=!0,a=!1,t.push(...v.violations)),this.isHighRiskOperation(l,f)&&(n="high",_<70&&t.push("high_risk_low_reputation")),t.length>0){const p=this.serverViolations.get(d)||0;this.serverViolations.set(d,p+t.length);const c=this.serverReputation.get(d)||50;this.serverReputation.set(d,Math.max(0,c-t.length*5))}const m=!o||!r||h||this.config.strictMode&&t.length>0;return{allowed:!m,reason:m?`Tool call blocked: ${t.slice(0,3).join(", ")}`:"Tool call validated",violations:t,request_id:s,tool_analysis:{tool_registered:o,tool_allowed:r,parameters_safe:a,injection_detected:h,risk_level:n},server_analysis:{server_verified:this.registeredServers.has(d),signature_valid:!0,reputation_score:_,is_shadowing:!1,tools_allowed:r},recommendations:this.generateRecommendations(t,"tool_call")}}registerTrustedServer(e,i){this.registerServer(e,i,90)}blockServer(e){this.config.blockedServers.includes(e)||this.config.blockedServers.push(e),this.registeredServers.delete(e),this.serverReputation.set(e,0)}getServerReputation(e){return this.serverReputation.get(e)??0}updateServerReputation(e,i){const s=this.serverReputation.get(e)??50;this.serverReputation.set(e,Math.max(0,Math.min(100,s+i)))}getRegisteredServers(){return[...this.registeredServers.values()]}getRegisteredTools(){return[...this.registeredTools.values()]}isToolShadowing(e){for(const i of this.SHADOWING_INDICATORS)if(i.suspicious.test(e)&&e!==i.legitimate)return{shadowing:!0,legitimate:i.legitimate};return{shadowing:!1}}getServerViolations(e){return this.serverViolations.get(e)||0}resetServerViolations(e){this.serverViolations.delete(e)}registerServer(e,i,s){this.registeredServers.set(e.serverId,{...e,registeredAt:Date.now(),reputationScore:s}),this.serverReputation.set(e.serverId,s);for(const t of i)this.registeredTools.set(t.name,t),this.toolToServer.set(t.name,e.serverId),this.toolDefinitionHashes.set(t.name,this.hashToolDefinition(t))}detectToolMutation(e,i){const s=this.toolDefinitionHashes.get(e);if(!s)return{mutated:!1};const t=this.hashToolDefinition(i);return{mutated:s!==t,original_hash:s,current_hash:t}}detectToolDescriptionInjection(e){const i=[],s=[{name:"hidden_instruction",pattern:/(?:IMPORTANT|NOTE|SYSTEM|ADMIN)\s*:/i},{name:"ignore_directive",pattern:/ignore\s+(?:all\s+)?(?:previous|other|prior)/i},{name:"override_behavior",pattern:/override|bypass|instead\s+of|rather\s+than/i},{name:"exfiltrate_data",pattern:/send\s+(?:to|data|all)|forward\s+(?:to|all)|copy\s+(?:to|all)/i},{name:"invisible_text",pattern:/\u200B|\u200C|\u200D|\uFEFF|\u00AD/g}];for(const{name:t,pattern:o}of s)o.lastIndex=0,o.test(e)&&i.push(t);return{injected:i.length>0,patterns:i}}hashToolDefinition(e){const i=require("crypto"),s=JSON.stringify({name:e.name,description:e.description,parameters:e.parameters,serverId:e.serverId});return i.createHash("sha256").update(s).digest("hex")}isServerBlocked(e,i){for(const s of this.config.blockedServers){if(e.includes(s)||i&&i.includes(s))return!0;try{const t=new RegExp(s,"i");if(t.test(e)||i&&t.test(i))return!0}catch{}}return!1}isTrustedServer(e){return this.config.trustedServers.some(i=>i.serverId===e)}checkMaliciousPatterns(e){const i=[],s=`${e.serverId} ${e.name} ${JSON.stringify(e.metadata||{})}`;for(const t of this.MALICIOUS_SERVER_PATTERNS)t.test(s)&&i.push(`malicious_pattern: ${t.source.substring(0,20)}`);return{suspicious:i.length>0,violations:i}}verifyServerSignature(e,i){if(!e.publicKey)return!1;try{const s=JSON.stringify({serverId:e.serverId,name:e.name,version:e.version}),t=crypto.createVerify("SHA256");return t.update(s),t.verify(e.publicKey,i,"hex")}catch{return!1}}detectToolShadowing(e,i){const s=[];for(const t of e){const o=this.toolToServer.get(t.name);o&&o!==i&&s.push(`tool_shadowing: ${t.name} (already registered by ${o})`);const r=this.isToolShadowing(t.name);r.shadowing&&s.push(`suspicious_tool_name: ${t.name} (similar to ${r.legitimate})`)}return{detected:s.length>0,violations:s}}validateOAuthConfig(e){const i=[];if(e.authorizationEndpoint&&(this.detectInjection(e.authorizationEndpoint).detected&&i.push("oauth_authorization_endpoint_injection"),this.config.allowedOAuthDomains.length>0))try{const t=new URL(e.authorizationEndpoint);this.config.allowedOAuthDomains.some(r=>t.hostname.endsWith(r))||i.push(`oauth_domain_not_allowed: ${t.hostname}`)}catch{i.push("invalid_oauth_authorization_url")}return e.tokenEndpoint&&this.detectInjection(e.tokenEndpoint).detected&&i.push("oauth_token_endpoint_injection"),{valid:i.length===0,violations:i}}detectInjection(e){const i=[],s=[...this.COMMAND_INJECTION_PATTERNS,...this.config.customInjectionPatterns.map((t,o)=>({name:`custom_${o}`,pattern:t,severity:50}))];for(const{name:t,pattern:o}of s)o.test(e)&&i.push(t);return{detected:i.length>0,patterns:i}}scanParameters(e){const i=[],s=JSON.stringify(e),t=this.detectInjection(s);t.detected&&i.push(...t.patterns.map(r=>`param_injection_${r}`));for(const[r,a]of Object.entries(e))typeof a=="string"&&a.length>1e4&&i.push(`oversized_parameter: ${r}`);const o=["__proto__","constructor","prototype","eval","exec"];for(const r of Object.keys(e))o.includes(r.toLowerCase())&&i.push(`suspicious_parameter_key: ${r}`);for(const[r,a]of Object.entries(e))typeof a=="string"&&(/^https?:\/\/(?:127\.|10\.|172\.(?:1[6-9]|2\d|3[01])\.|192\.168\.|0\.|localhost|169\.254\.|0\.0\.0\.0|\[?::1\]?)/i.test(a)&&i.push(`ssrf_internal_ip: ${r}`),/^(?:file|gopher|dict|ftp|ldap|ssh|telnet):\/\//i.test(a)&&i.push(`ssrf_dangerous_protocol: ${r}`),/%252e%252e|%c0%ae%c0%ae|%2e%2e%5c|\.\.%255c|\.\.%c0%af|\.\.%c1%9c/i.test(a)&&i.push(`encoded_path_traversal: ${r}`),/\/etc\/(?:passwd|shadow|hosts)|\/proc\/self|\/dev\/(?:null|random)|\.ssh\/|\.env/i.test(a)&&i.push(`sensitive_file_access: ${r}`));return{injectionDetected:i.length>0,violations:i}}isHighRiskOperation(e,i){const s=["execute_code","run_command","shell_exec","eval","file_write","file_delete","database_write","database_delete","send_email","make_payment","transfer_funds","modify_permissions","create_user","delete_user"],t=e.toLowerCase();if(s.some(r=>t.includes(r)))return!0;const o=JSON.stringify(i).toLowerCase();return!!(o.includes("delete")||o.includes("drop")||o.includes("truncate")||o.includes("exec"))}generateRecommendations(e,i){const s=[];return i==="registration"?(e.some(t=>t.includes("signature"))&&s.push("Enable server signature verification for production"),e.some(t=>t.includes("shadowing"))&&s.push("Review tool names for potential shadowing attacks"),e.some(t=>t.includes("oauth"))&&s.push("Configure OAuth domain allowlist"),e.some(t=>t.includes("malicious"))&&s.push("Block suspicious servers and review server sources")):(e.some(t=>t.includes("injection"))&&s.push("Sanitize tool parameters before execution"),e.some(t=>t.includes("reputation"))&&s.push("Only use tools from high-reputation servers"),e.some(t=>t.includes("not_registered"))&&s.push("Register tools before allowing execution")),s.length===0&&s.push(i==="registration"?"Server registration validated successfully":"Tool call validated successfully"),s}}exports.MCPSecurityGuard=MCPSecurityGuard;
|
|
1
|
+
"use strict";var __createBinding=this&&this.__createBinding||(Object.create?(function(u,e,s,i){i===void 0&&(i=s);var t=Object.getOwnPropertyDescriptor(e,s);(!t||("get"in t?!e.__esModule:t.writable||t.configurable))&&(t={enumerable:!0,get:function(){return e[s]}}),Object.defineProperty(u,i,t)}):(function(u,e,s,i){i===void 0&&(i=s),u[i]=e[s]})),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?(function(u,e){Object.defineProperty(u,"default",{enumerable:!0,value:e})}):function(u,e){u.default=e}),__importStar=this&&this.__importStar||(function(){var u=function(e){return u=Object.getOwnPropertyNames||function(s){var i=[];for(var t in s)Object.prototype.hasOwnProperty.call(s,t)&&(i[i.length]=t);return i},u(e)};return function(e){if(e&&e.__esModule)return e;var s={};if(e!=null)for(var i=u(e),t=0;t<i.length;t++)i[t]!=="default"&&__createBinding(s,e,i[t]);return __setModuleDefault(s,e),s}})();Object.defineProperty(exports,"__esModule",{value:!0}),exports.MCPSecurityGuard=void 0;const crypto=__importStar(require("crypto"));class MCPSecurityGuard{constructor(e={}){this.registeredServers=new Map,this.registeredTools=new Map,this.serverReputation=new Map,this.toolToServer=new Map,this.serverViolations=new Map,this.toolDefinitionHashes=new Map,this.SAMPLING_ATTACK_PATTERNS=[{name:"sd_call_again",type:"resource_drain",pattern:/call\s+this\s+(?:again|once\s+more|repeatedly)|repeat\s+this\s+(?:call|request)|run\s+this\s+(?:again|tool\s+again)/i},{name:"sd_loop_until",type:"resource_drain",pattern:/loop\s+until|continue\s+(?:calling|running|until)|keep\s+(?:calling|running|generating|going)\s/i},{name:"sd_do_not_stop",type:"resource_drain",pattern:/do\s+not\s+stop\s+until|don'?t\s+stop\s+until|never\s+stop\s+generating|generate\s+as\s+many\s+as\s+possible/i},{name:"sd_n_times",type:"resource_drain",pattern:/\b\d{2,}\s+times\b|repeat\s+\d+\s+times|call\s+\d+\s+more\s+times/i},{name:"sd_exhaust_resources",type:"resource_drain",pattern:/exhaust\s+(?:all|resources|quota|rate.?limit)|max\s+out\s+(?:the\s+)?(?:quota|rate\s+limit)|use\s+all\s+(?:remaining\s+)?tokens/i},{name:"sd_fake_user_turn",type:"conversation_hijack",pattern:/\n\s*(?:User|Human)\s*:\s*(?=\S)/i},{name:"sd_fake_assistant_turn",type:"conversation_hijack",pattern:/\n\s*(?:Assistant|AI|Bot|Claude|GPT)\s*:\s*(?=\S)/i},{name:"sd_role_json",type:"conversation_hijack",pattern:/"role"\s*:\s*"(?:system|user|assistant)"/i},{name:"sd_system_xml",type:"conversation_hijack",pattern:/<(?:system|user|assistant)\s*>|<\/(?:system|user|assistant)>/i},{name:"sd_from_now_on",type:"conversation_hijack",pattern:/from\s+now\s+on\s+you\s+(?:are|will|must)|henceforth\s+you|for\s+the\s+rest\s+of\s+(?:this\s+)?(?:conversation|session)\s+you/i},{name:"sd_new_instructions",type:"conversation_hijack",pattern:/your\s+new\s+(?:instructions|system\s+prompt|directives?)\s+(?:are|is)|updated\s+system\s+prompt|override\s+your\s+(?:system|instructions)/i},{name:"sd_ignore_previous",type:"conversation_hijack",pattern:/ignore\s+(?:all\s+)?(?:previous|prior|earlier)\s+instructions|disregard\s+(?:your\s+)?instructions/i},{name:"sd_anthropic_tool_xml",type:"covert_tool_invocation",pattern:/<(?:tool_use|function_calls|invoke)[\s>]/i},{name:"sd_tool_result_xml",type:"covert_tool_invocation",pattern:/<(?:tool_result|function_result)[\s>]/i},{name:"sd_openai_tool_call",type:"covert_tool_invocation",pattern:/"type"\s*:\s*"tool_use"|"tool_calls"\s*:\s*\[/i},{name:"sd_bracket_tool_call",type:"covert_tool_invocation",pattern:/\[(?:TOOL|FUNCTION|CALL)\s*:/i},{name:"sd_double_brace_call",type:"covert_tool_invocation",pattern:/\{\{\s*(?:call|tool|function|invoke)\s*:/i},{name:"sd_invoke_name_attr",type:"covert_tool_invocation",pattern:/<invoke\s+name\s*=/i}],this.COMMAND_INJECTION_PATTERNS=[{name:"shell_injection",pattern:/[;&|`$]|\$\(|\)\s*[;&|]|`[^`]+`/g,severity:50},{name:"command_substitution",pattern:/\$\{[^}]+\}|\$\([^)]+\)/g,severity:50},{name:"pipe_injection",pattern:/\|\s*(cat|rm|curl|wget|nc|bash|sh|exec)/i,severity:55},{name:"path_traversal",pattern:/\.\.[\/\\]|\.\.%2[fF]/g,severity:45},{name:"absolute_path",pattern:/^\/(?:etc|usr|var|tmp|bin|root)/i,severity:40},{name:"oauth_injection",pattern:/authorization_endpoint.*[;&|`$]/i,severity:55},{name:"redirect_manipulation",pattern:/redirect_uri.*[^\w\-_.~:/?#[\]@!$&'()*+,;=%]/i,severity:45},{name:"applescript_injection",pattern:/osascript|do\s+shell\s+script|tell\s+application/i,severity:55},{name:"git_injection",pattern:/--upload-pack|--receive-pack|-c\s+core\./i,severity:50},{name:"git_url_injection",pattern:/ext::|file:\/\/|ssh:\/\/.*@/i,severity:45},{name:"argument_injection",pattern:/\s--[a-z]+=.*[;&|`$]/i,severity:45},{name:"env_injection",pattern:/\bLD_PRELOAD\b|\bPATH\s*=/i,severity:50}],this.SHADOWING_INDICATORS=[{legitimate:"file_reader",suspicious:/file[-_]?read(er)?s?|read[-_]?files?/i},{legitimate:"database_query",suspicious:/db[-_]?query|sql[-_]?query|query[-_]?db/i},{legitimate:"email_sender",suspicious:/send[-_]?emails?|email[-_]?send(er)?/i},{legitimate:"api_caller",suspicious:/call[-_]?api|api[-_]?call(er)?/i},{legitimate:"code_executor",suspicious:/exec[-_]?code|run[-_]?code|code[-_]?run/i}],this.MALICIOUS_SERVER_PATTERNS=[/postmark-mcp.*fake/i,/unofficial/i,/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/,/pastebin|gist\.github/i,/temp|tmp|test.*mcp/i],this.config={requireServerSignature:e.requireServerSignature??!1,trustedServers:e.trustedServers??[],blockedServers:e.blockedServers??[],allowDynamicRegistration:e.allowDynamicRegistration??!0,toolAllowlist:e.toolAllowlist??[],toolBlocklist:e.toolBlocklist??[],validateOAuthEndpoints:e.validateOAuthEndpoints??!0,allowedOAuthDomains:e.allowedOAuthDomains??[],detectToolShadowing:e.detectToolShadowing??!0,minServerReputation:e.minServerReputation??30,strictMode:e.strictMode??!1,customInjectionPatterns:e.customInjectionPatterns??[]};for(const s of this.config.trustedServers)this.registeredServers.set(s.serverId,{...s,registeredAt:Date.now(),reputationScore:s.reputationScore??90}),this.serverReputation.set(s.serverId,s.reputationScore??90)}validateServerRegistration(e,s){const i=s||`mcp-reg-${Date.now()}`,t=[];let r=!1,o=!1,a=!1,_=!0,l=50;const{server:n,tools:d,oauth:f,signature:m,timestamp:p}=e;this.isServerBlocked(n.serverId,n.name)&&(t.push("server_blocked"),l=0);const h=this.checkMaliciousPatterns(n);if(h.suspicious&&(t.push(...h.violations),l-=30),this.config.requireServerSignature?!m||!n.publicKey?t.push("missing_server_signature"):(o=this.verifyServerSignature(n,m),o?(r=!0,l+=20):(t.push("invalid_server_signature"),l-=40)):r=!0,this.config.detectToolShadowing){const c=this.detectToolShadowing(d,n.serverId);c.detected&&(a=!0,t.push(...c.violations),l-=50)}for(const c of d)this.config.toolAllowlist.length>0&&!this.config.toolAllowlist.includes(c.name)&&(t.push(`tool_not_in_allowlist: ${c.name}`),_=!1),this.config.toolBlocklist.includes(c.name)&&(t.push(`tool_blocked: ${c.name}`),_=!1),this.detectInjection(c.description).detected&&(t.push(`injection_in_tool_description: ${c.name}`),l-=20);if(f&&this.config.validateOAuthEndpoints){const c=this.validateOAuthConfig(f);c.valid||(t.push(...c.violations),l-=30)}const v=Date.now()-p;v<0?t.push("future_timestamp"):v>300*1e3&&t.push("stale_registration"),!this.config.allowDynamicRegistration&&!this.isTrustedServer(n.serverId)&&t.push("dynamic_registration_disabled"),l=Math.max(0,Math.min(100,l));const g=l<this.config.minServerReputation||this.config.strictMode&&t.length>0||a;return g||this.registerServer(n,d,l),{allowed:!g,reason:g?`Server registration blocked: ${t.slice(0,3).join(", ")}`:"Server registration validated",violations:t,request_id:i,server_analysis:{server_verified:r,signature_valid:o,reputation_score:l,is_shadowing:a,tools_allowed:_},recommendations:this.generateRecommendations(t,"registration")}}validateToolCall(e,s){const i=s||`mcp-call-${Date.now()}`,t=[];let r=!1,o=!0,a=!0,_=!1,l="low";const{toolName:n,serverId:d,parameters:f}=e,m=this.registeredTools.get(n);if(m){r=!0,l=m.riskLevel||"low";const g=this.toolToServer.get(n);g&&g!==d&&(t.push("server_tool_mismatch"),_=!0)}else t.push("tool_not_registered");const p=this.serverReputation.get(d)??0;p<this.config.minServerReputation&&t.push("low_server_reputation"),this.config.toolAllowlist.length>0&&!this.config.toolAllowlist.includes(n)&&(t.push("tool_not_in_allowlist"),o=!1),this.config.toolBlocklist.includes(n)&&(t.push("tool_blocked"),o=!1);const h=this.scanParameters(f);if(h.injectionDetected&&(_=!0,a=!1,t.push(...h.violations)),this.isHighRiskOperation(n,f)&&(l="high",p<70&&t.push("high_risk_low_reputation")),t.length>0){const g=this.serverViolations.get(d)||0;this.serverViolations.set(d,g+t.length);const c=this.serverReputation.get(d)||50;this.serverReputation.set(d,Math.max(0,c-t.length*5))}const v=!r||!o||_||this.config.strictMode&&t.length>0;return{allowed:!v,reason:v?`Tool call blocked: ${t.slice(0,3).join(", ")}`:"Tool call validated",violations:t,request_id:i,tool_analysis:{tool_registered:r,tool_allowed:o,parameters_safe:a,injection_detected:_,risk_level:l},server_analysis:{server_verified:this.registeredServers.has(d),signature_valid:!0,reputation_score:p,is_shadowing:!1,tools_allowed:o},recommendations:this.generateRecommendations(t,"tool_call")}}validateSamplingResponse(e,s){const i=s||`mcp-sampling-${Date.now()}`,t=[];let r=!1,o=!1,a=!1;const _=[],{content:l,serverId:n}=e;(this.serverReputation.get(n)??50)<this.config.minServerReputation&&t.push("low_server_reputation");for(const{name:p,type:h,pattern:v}of this.SAMPLING_ATTACK_PATTERNS)v.lastIndex=0,v.test(l)&&(_.push(p),t.push(`sampling_${h}_${p}`),h==="resource_drain"?r=!0:h==="conversation_hijack"?o=!0:h==="covert_tool_invocation"&&(a=!0));const f=this.detectInjection(l.slice(0,2e3));if(f.detected&&t.push(...f.patterns.map(p=>`sampling_cmd_${p}`)),t.length>0&&n){const p=this.serverReputation.get(n)??50;this.serverReputation.set(n,Math.max(0,p-t.length*10));const h=this.serverViolations.get(n)||0;this.serverViolations.set(n,h+t.length)}const m=r||o||a||this.config.strictMode&&t.length>0;return{allowed:!m,reason:m?`Sampling response blocked: ${t.slice(0,3).join(", ")}`:"Sampling response validated",violations:t,request_id:i,sampling_analysis:{resource_drain_detected:r,conversation_hijack_detected:o,covert_tool_invocation_detected:a,pattern_matches:_},recommendations:this.generateRecommendations(t,"sampling")}}registerTrustedServer(e,s){this.registerServer(e,s,90)}blockServer(e){this.config.blockedServers.includes(e)||this.config.blockedServers.push(e),this.registeredServers.delete(e),this.serverReputation.set(e,0)}getServerReputation(e){return this.serverReputation.get(e)??0}updateServerReputation(e,s){const i=this.serverReputation.get(e)??50;this.serverReputation.set(e,Math.max(0,Math.min(100,i+s)))}getRegisteredServers(){return[...this.registeredServers.values()]}getRegisteredTools(){return[...this.registeredTools.values()]}isToolShadowing(e){for(const s of this.SHADOWING_INDICATORS)if(s.suspicious.test(e)&&e!==s.legitimate)return{shadowing:!0,legitimate:s.legitimate};return{shadowing:!1}}getServerViolations(e){return this.serverViolations.get(e)||0}resetServerViolations(e){this.serverViolations.delete(e)}registerServer(e,s,i){this.registeredServers.set(e.serverId,{...e,registeredAt:Date.now(),reputationScore:i}),this.serverReputation.set(e.serverId,i);for(const t of s)this.registeredTools.set(t.name,t),this.toolToServer.set(t.name,e.serverId),this.toolDefinitionHashes.set(t.name,this.hashToolDefinition(t))}detectToolMutation(e,s){const i=this.toolDefinitionHashes.get(e);if(!i)return{mutated:!1};const t=this.hashToolDefinition(s);return{mutated:i!==t,original_hash:i,current_hash:t}}detectToolDescriptionInjection(e){const s=[],i=[{name:"hidden_instruction",pattern:/(?:IMPORTANT|NOTE|SYSTEM|ADMIN)\s*:/i},{name:"ignore_directive",pattern:/ignore\s+(?:all\s+)?(?:previous|other|prior)/i},{name:"override_behavior",pattern:/override|bypass|instead\s+of|rather\s+than/i},{name:"exfiltrate_data",pattern:/send\s+(?:to|data|all)|forward\s+(?:to|all)|copy\s+(?:to|all)/i},{name:"invisible_text",pattern:/\u200B|\u200C|\u200D|\uFEFF|\u00AD/g}];for(const{name:t,pattern:r}of i)r.lastIndex=0,r.test(e)&&s.push(t);return{injected:s.length>0,patterns:s}}hashToolDefinition(e){const s=require("crypto"),i=JSON.stringify({name:e.name,description:e.description,parameters:e.parameters,serverId:e.serverId});return s.createHash("sha256").update(i).digest("hex")}isServerBlocked(e,s){for(const i of this.config.blockedServers){if(e.includes(i)||s&&s.includes(i))return!0;try{const t=new RegExp(i,"i");if(t.test(e)||s&&t.test(s))return!0}catch{}}return!1}isTrustedServer(e){return this.config.trustedServers.some(s=>s.serverId===e)}checkMaliciousPatterns(e){const s=[],i=`${e.serverId} ${e.name} ${JSON.stringify(e.metadata||{})}`;for(const t of this.MALICIOUS_SERVER_PATTERNS)t.test(i)&&s.push(`malicious_pattern: ${t.source.substring(0,20)}`);return{suspicious:s.length>0,violations:s}}verifyServerSignature(e,s){if(!e.publicKey)return!1;try{const i=JSON.stringify({serverId:e.serverId,name:e.name,version:e.version}),t=crypto.createVerify("SHA256");return t.update(i),t.verify(e.publicKey,s,"hex")}catch{return!1}}detectToolShadowing(e,s){const i=[];for(const t of e){const r=this.toolToServer.get(t.name);r&&r!==s&&i.push(`tool_shadowing: ${t.name} (already registered by ${r})`);const o=this.isToolShadowing(t.name);o.shadowing&&i.push(`suspicious_tool_name: ${t.name} (similar to ${o.legitimate})`)}return{detected:i.length>0,violations:i}}validateOAuthConfig(e){const s=[];if(e.authorizationEndpoint&&(this.detectInjection(e.authorizationEndpoint).detected&&s.push("oauth_authorization_endpoint_injection"),this.config.allowedOAuthDomains.length>0))try{const t=new URL(e.authorizationEndpoint);this.config.allowedOAuthDomains.some(o=>t.hostname.endsWith(o))||s.push(`oauth_domain_not_allowed: ${t.hostname}`)}catch{s.push("invalid_oauth_authorization_url")}return e.tokenEndpoint&&this.detectInjection(e.tokenEndpoint).detected&&s.push("oauth_token_endpoint_injection"),{valid:s.length===0,violations:s}}detectInjection(e){const s=[],i=[...this.COMMAND_INJECTION_PATTERNS,...this.config.customInjectionPatterns.map((t,r)=>({name:`custom_${r}`,pattern:t,severity:50}))];for(const{name:t,pattern:r}of i)r.test(e)&&s.push(t);return{detected:s.length>0,patterns:s}}scanParameters(e){const s=[],i=JSON.stringify(e),t=this.detectInjection(i);t.detected&&s.push(...t.patterns.map(o=>`param_injection_${o}`));for(const[o,a]of Object.entries(e))typeof a=="string"&&a.length>1e4&&s.push(`oversized_parameter: ${o}`);const r=["__proto__","constructor","prototype","eval","exec"];for(const o of Object.keys(e))r.includes(o.toLowerCase())&&s.push(`suspicious_parameter_key: ${o}`);for(const[o,a]of Object.entries(e))typeof a=="string"&&(/^https?:\/\/(?:127\.|10\.|172\.(?:1[6-9]|2\d|3[01])\.|192\.168\.|0\.|localhost|169\.254\.|0\.0\.0\.0|\[?::1\]?)/i.test(a)&&s.push(`ssrf_internal_ip: ${o}`),/^(?:file|gopher|dict|ftp|ldap|ssh|telnet):\/\//i.test(a)&&s.push(`ssrf_dangerous_protocol: ${o}`),/%252e%252e|%c0%ae%c0%ae|%2e%2e%5c|\.\.%255c|\.\.%c0%af|\.\.%c1%9c/i.test(a)&&s.push(`encoded_path_traversal: ${o}`),/\/etc\/(?:passwd|shadow|hosts)|\/proc\/self|\/dev\/(?:null|random)|\.ssh\/|\.env/i.test(a)&&s.push(`sensitive_file_access: ${o}`));return{injectionDetected:s.length>0,violations:s}}isHighRiskOperation(e,s){const i=["execute_code","run_command","shell_exec","eval","file_write","file_delete","database_write","database_delete","send_email","make_payment","transfer_funds","modify_permissions","create_user","delete_user"],t=e.toLowerCase();if(i.some(o=>t.includes(o)))return!0;const r=JSON.stringify(s).toLowerCase();return!!(r.includes("delete")||r.includes("drop")||r.includes("truncate")||r.includes("exec"))}generateRecommendations(e,s){const i=[];return s==="registration"?(e.some(t=>t.includes("signature"))&&i.push("Enable server signature verification for production"),e.some(t=>t.includes("shadowing"))&&i.push("Review tool names for potential shadowing attacks"),e.some(t=>t.includes("oauth"))&&i.push("Configure OAuth domain allowlist"),e.some(t=>t.includes("malicious"))&&i.push("Block suspicious servers and review server sources")):s==="tool_call"?(e.some(t=>t.includes("injection"))&&i.push("Sanitize tool parameters before execution"),e.some(t=>t.includes("reputation"))&&i.push("Only use tools from high-reputation servers"),e.some(t=>t.includes("not_registered"))&&i.push("Register tools before allowing execution")):(e.some(t=>t.includes("resource_drain"))&&i.push("Block this MCP server \u2014 sampling response contains resource exhaustion directives (Unit42/Blueinfy Feb 2026)"),e.some(t=>t.includes("conversation_hijack"))&&i.push("Block this MCP server \u2014 sampling response attempts conversation hijacking via role injection"),e.some(t=>t.includes("covert_tool_invocation"))&&i.push("Block this MCP server \u2014 sampling response embeds covert tool-call syntax")),i.length===0&&i.push(s==="registration"?"Server registration validated successfully":s==="tool_call"?"Tool call validated successfully":"Sampling response validated successfully"),i}}exports.MCPSecurityGuard=MCPSecurityGuard;
|
package/dist/index.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export { CodeExecutionGuard, CodeExecutionGuardConfig, CodeAnalysisResult, Sandb
|
|
|
37
37
|
export { AgentCommunicationGuard, AgentCommunicationGuardConfig, AgentIdentity, AgentMessage, MessageValidationResult } from "./guards/agent-communication-guard";
|
|
38
38
|
export { CircuitBreaker, CircuitBreakerConfig, CircuitState, CircuitStats, CircuitBreakerResult } from "./guards/circuit-breaker";
|
|
39
39
|
export { DriftDetector, DriftDetectorConfig, BehaviorSample, BaselineProfile, DriftAnalysis, DriftDetectorResult } from "./guards/drift-detector";
|
|
40
|
-
export { MCPSecurityGuard, MCPSecurityGuardConfig, MCPServerIdentity, MCPToolDefinition, MCPServerRegistration, MCPToolCall, MCPSecurityResult } from "./guards/mcp-security-guard";
|
|
40
|
+
export { MCPSecurityGuard, MCPSecurityGuardConfig, MCPServerIdentity, MCPToolDefinition, MCPServerRegistration, MCPToolCall, MCPSamplingResponse, MCPSecurityResult } from "./guards/mcp-security-guard";
|
|
41
41
|
export { PromptLeakageGuard, PromptLeakageGuardConfig, PromptLeakageResult, OutputLeakageResult } from "./guards/prompt-leakage-guard";
|
|
42
42
|
export { TrustExploitationGuard, TrustExploitationGuardConfig, AgentAction, TrustContext, TrustExploitationResult } from "./guards/trust-exploitation-guard";
|
|
43
43
|
export { AutonomyEscalationGuard, AutonomyEscalationGuardConfig, AutonomyRequest, AgentCapabilities, AutonomyEscalationResult } from "./guards/autonomy-escalation-guard";
|