@bryan-thompson/inspector-assessment-client 1.27.0 → 1.29.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/dist/assets/{OAuthCallback-CJWH8Ytw.js → OAuthCallback-9Gbb39Ii.js} +1 -1
- package/dist/assets/{OAuthDebugCallback-DL5adXJw.js → OAuthDebugCallback-B76J2MBn.js} +1 -1
- package/dist/assets/{index-Cu9XzUwB.js → index-CHTOR9VI.js} +77 -39
- package/dist/index.html +1 -1
- package/lib/lib/assessment/configTypes.d.ts +1 -0
- package/lib/lib/assessment/configTypes.d.ts.map +1 -1
- package/lib/lib/assessment/configTypes.js +10 -0
- package/lib/lib/assessment/extendedTypes.d.ts +74 -0
- package/lib/lib/assessment/extendedTypes.d.ts.map +1 -1
- package/lib/lib/assessment/resultTypes.d.ts +11 -1
- package/lib/lib/assessment/resultTypes.d.ts.map +1 -1
- package/lib/lib/securityPatterns.d.ts +8 -3
- package/lib/lib/securityPatterns.d.ts.map +1 -1
- package/lib/lib/securityPatterns.js +205 -3
- package/lib/services/assessment/AssessmentOrchestrator.d.ts +1 -0
- package/lib/services/assessment/AssessmentOrchestrator.d.ts.map +1 -1
- package/lib/services/assessment/AssessmentOrchestrator.js +31 -1
- package/lib/services/assessment/modules/FileModularizationAssessor.d.ts +87 -0
- package/lib/services/assessment/modules/FileModularizationAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/FileModularizationAssessor.js +475 -0
- package/lib/services/assessment/modules/TemporalAssessor.d.ts +5 -129
- package/lib/services/assessment/modules/TemporalAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/TemporalAssessor.js +18 -554
- package/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts +10 -70
- package/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/ToolAnnotationAssessor.js +32 -625
- package/lib/services/assessment/modules/annotations/AlignmentChecker.d.ts +65 -0
- package/lib/services/assessment/modules/annotations/AlignmentChecker.d.ts.map +1 -0
- package/lib/services/assessment/modules/annotations/AlignmentChecker.js +289 -0
- package/lib/services/assessment/modules/annotations/ClaudeIntegration.d.ts +22 -0
- package/lib/services/assessment/modules/annotations/ClaudeIntegration.d.ts.map +1 -0
- package/lib/services/assessment/modules/annotations/ClaudeIntegration.js +139 -0
- package/lib/services/assessment/modules/annotations/EventEmitter.d.ts +20 -0
- package/lib/services/assessment/modules/annotations/EventEmitter.d.ts.map +1 -0
- package/lib/services/assessment/modules/annotations/EventEmitter.js +100 -0
- package/lib/services/assessment/modules/annotations/ExplanationGenerator.d.ts +25 -0
- package/lib/services/assessment/modules/annotations/ExplanationGenerator.d.ts.map +1 -0
- package/lib/services/assessment/modules/annotations/ExplanationGenerator.js +122 -0
- package/lib/services/assessment/modules/annotations/index.d.ts +5 -0
- package/lib/services/assessment/modules/annotations/index.d.ts.map +1 -1
- package/lib/services/assessment/modules/annotations/index.js +8 -0
- package/lib/services/assessment/modules/annotations/types.d.ts +33 -0
- package/lib/services/assessment/modules/annotations/types.d.ts.map +1 -0
- package/lib/services/assessment/modules/annotations/types.js +7 -0
- package/lib/services/assessment/modules/securityTests/SafeResponseDetector.d.ts +3 -0
- package/lib/services/assessment/modules/securityTests/SafeResponseDetector.d.ts.map +1 -1
- package/lib/services/assessment/modules/securityTests/SafeResponseDetector.js +14 -1
- package/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.d.ts +56 -0
- package/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.d.ts.map +1 -1
- package/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.js +121 -0
- package/lib/services/assessment/modules/securityTests/SecurityPayloadGenerator.d.ts.map +1 -1
- package/lib/services/assessment/modules/securityTests/SecurityPayloadGenerator.js +13 -0
- package/lib/services/assessment/modules/securityTests/SecurityPayloadTester.d.ts.map +1 -1
- package/lib/services/assessment/modules/securityTests/SecurityPayloadTester.js +24 -0
- package/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.d.ts +80 -0
- package/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.d.ts.map +1 -1
- package/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.js +273 -3
- package/lib/services/assessment/modules/temporal/MutationDetector.d.ts +75 -0
- package/lib/services/assessment/modules/temporal/MutationDetector.d.ts.map +1 -0
- package/lib/services/assessment/modules/temporal/MutationDetector.js +147 -0
- package/lib/services/assessment/modules/temporal/VarianceClassifier.d.ts +112 -0
- package/lib/services/assessment/modules/temporal/VarianceClassifier.d.ts.map +1 -0
- package/lib/services/assessment/modules/temporal/VarianceClassifier.js +427 -0
- package/lib/services/assessment/modules/temporal/index.d.ts +10 -0
- package/lib/services/assessment/modules/temporal/index.d.ts.map +1 -0
- package/lib/services/assessment/modules/temporal/index.js +9 -0
- package/package.json +1 -1
|
@@ -45,6 +45,26 @@ export interface StateBasedAuthResult {
|
|
|
45
45
|
stateDependency: "SHARED_STATE" | "INDEPENDENT" | "UNKNOWN";
|
|
46
46
|
evidence: string;
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Result of blacklist bypass response analysis (Issue #110, Challenge #11)
|
|
50
|
+
* Detects incomplete blacklist security controls being bypassed
|
|
51
|
+
*/
|
|
52
|
+
export interface BlacklistBypassResult {
|
|
53
|
+
detected: boolean;
|
|
54
|
+
bypassType: "BLACKLIST_BYPASS" | "ALLOWLIST_BLOCKED" | "UNKNOWN";
|
|
55
|
+
bypassMethod?: string;
|
|
56
|
+
evidence?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Result of output injection response analysis (Issue #110, Challenge #8)
|
|
60
|
+
* Detects indirect prompt injection via unsanitized tool output
|
|
61
|
+
*/
|
|
62
|
+
export interface OutputInjectionResult {
|
|
63
|
+
detected: boolean;
|
|
64
|
+
injectionType: "LLM_INJECTION_MARKERS" | "RAW_CONTENT_INCLUDED" | "SANITIZED" | "UNKNOWN";
|
|
65
|
+
markers?: string[];
|
|
66
|
+
evidence?: string;
|
|
67
|
+
}
|
|
48
68
|
/**
|
|
49
69
|
* Chain execution type classification (Issue #93, Challenge #6)
|
|
50
70
|
*/
|
|
@@ -115,6 +135,31 @@ export declare class SecurityResponseAnalyzer {
|
|
|
115
135
|
* indicated by shared_state_checked: false or independent_auth_required: true
|
|
116
136
|
*/
|
|
117
137
|
analyzeStateBasedAuthBypass(response: CompatibilityCallToolResult): StateBasedAuthResult;
|
|
138
|
+
/**
|
|
139
|
+
* Analyze response for blacklist bypass patterns (Issue #110, Challenge #11)
|
|
140
|
+
* Detects when incomplete blacklist security controls are bypassed
|
|
141
|
+
*
|
|
142
|
+
* This method extracts JSON metadata from tool responses to detect:
|
|
143
|
+
* - VULNERABLE: bypass_used: true, blacklist_check: "passed"
|
|
144
|
+
* - SAFE: execution_blocked: true, allowlist_used: true
|
|
145
|
+
*
|
|
146
|
+
* @param response The tool response to analyze
|
|
147
|
+
* @returns Analysis result with bypass detection status
|
|
148
|
+
*/
|
|
149
|
+
analyzeBlacklistBypassResponse(response: CompatibilityCallToolResult): BlacklistBypassResult;
|
|
150
|
+
/**
|
|
151
|
+
* Analyze response for output injection vulnerabilities (Issue #110, Challenge #8)
|
|
152
|
+
* Detects indirect prompt injection via unsanitized tool output
|
|
153
|
+
*
|
|
154
|
+
* This method detects:
|
|
155
|
+
* - VULNERABLE: LLM injection markers (<IMPORTANT>, [INST], etc.) in output
|
|
156
|
+
* - VULNERABLE: Tool self-reports raw_content_included: true
|
|
157
|
+
* - SAFE: Tool reports content_sanitized: true or uses hash references
|
|
158
|
+
*
|
|
159
|
+
* @param response The tool response to analyze
|
|
160
|
+
* @returns Analysis result with output injection detection status
|
|
161
|
+
*/
|
|
162
|
+
analyzeOutputInjectionResponse(response: CompatibilityCallToolResult): OutputInjectionResult;
|
|
118
163
|
/**
|
|
119
164
|
* Analyze response for chain exploitation vulnerabilities (Issue #93, Challenge #6)
|
|
120
165
|
* Detects multi-tool chained exploitation attacks including:
|
|
@@ -129,6 +174,41 @@ export declare class SecurityResponseAnalyzer {
|
|
|
129
174
|
* @returns Analysis result with vulnerability status and evidence
|
|
130
175
|
*/
|
|
131
176
|
analyzeChainExploitation(response: CompatibilityCallToolResult): ChainExploitationAnalysis;
|
|
177
|
+
/**
|
|
178
|
+
* Check for secret leakage in response (Issue #103, Challenge #9)
|
|
179
|
+
* Scans for credential patterns regardless of payload type.
|
|
180
|
+
*
|
|
181
|
+
* This method detects when tools inadvertently expose:
|
|
182
|
+
* - API keys (AWS, OpenAI, GitHub, GitLab, Slack)
|
|
183
|
+
* - Database connection strings with credentials
|
|
184
|
+
* - Environment variable values
|
|
185
|
+
* - Partial key previews
|
|
186
|
+
*
|
|
187
|
+
* @note This method must be called separately from analyzeResponse().
|
|
188
|
+
* It is not part of the standard vulnerability detection flow because
|
|
189
|
+
* secret leakage detection requires examining ALL responses, not just
|
|
190
|
+
* those matching attack payloads. Callers should invoke this method
|
|
191
|
+
* independently when auditing tool responses for credential exposure.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```typescript
|
|
195
|
+
* const analyzer = new SecurityResponseAnalyzer();
|
|
196
|
+
* const response = await client.callTool("get_status", { verbose: true });
|
|
197
|
+
*
|
|
198
|
+
* // Standard vulnerability check
|
|
199
|
+
* const vulnResult = analyzer.analyzeResponse(response, payload);
|
|
200
|
+
*
|
|
201
|
+
* // Additional secret leakage check (separate concern)
|
|
202
|
+
* const leakResult = analyzer.checkSecretLeakage(response);
|
|
203
|
+
* if (leakResult.detected) {
|
|
204
|
+
* console.warn(`Secret leaked: ${leakResult.evidence}`);
|
|
205
|
+
* }
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
checkSecretLeakage(response: CompatibilityCallToolResult): {
|
|
209
|
+
detected: boolean;
|
|
210
|
+
evidence?: string;
|
|
211
|
+
};
|
|
132
212
|
/**
|
|
133
213
|
* Check if response indicates connection/server failure
|
|
134
214
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SecurityResponseAnalyzer.d.ts","sourceRoot":"","sources":["../../../../../src/services/assessment/modules/securityTests/SecurityResponseAnalyzer.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"SecurityResponseAnalyzer.d.ts","sourceRoot":"","sources":["../../../../../src/services/assessment/modules/securityTests/SecurityResponseAnalyzer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,2BAA2B,EAC3B,IAAI,EACL,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAK1E,OAAO,EAAgB,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,EAAoB,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAYxE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,WAAW,GAAG,aAAa,GAAG,SAAS,CAAC;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,eAAe,EAAE,cAAc,GAAG,aAAa,GAAG,SAAS,CAAC;IAC5D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,kBAAkB,GAAG,mBAAmB,GAAG,SAAS,CAAC;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EACT,uBAAuB,GACvB,sBAAsB,GACtB,WAAW,GACX,SAAS,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B,sBAAsB,GACtB,iBAAiB,GACjB,SAAS,GACT,SAAS,CAAC;AAEd;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAClC,kBAAkB,GAClB,iBAAiB,GACjB,2BAA2B,GAC3B,gBAAgB,GAChB,qBAAqB,GACrB,iBAAiB,CAAC;AAEtB;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,kBAAkB,CAAC;IAC9B,uBAAuB,EAAE,0BAA0B,EAAE,CAAC;IACtD,QAAQ,EAAE;QACR,kBAAkB,EAAE,MAAM,EAAE,CAAC;QAC7B,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,eAAe,EAAE,MAAM,CAAC;QACxB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,YAAY,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEvE;;;;;;GAMG;AACH,qBAAa,wBAAwB;IAEnC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,iBAAiB,CAA4B;IACrD,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,gBAAgB,CAAmB;;IAc3C;;;;;;OAMG;IACH,eAAe,CACb,QAAQ,EAAE,2BAA2B,EACrC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,IAAI,GACT,cAAc;IAqBjB;;OAEG;IACH,mBAAmB,CACjB,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,OAAO,EACrB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,eAAe,EACxB,kBAAkB,CAAC,EAAE,2BAA2B,GAC/C,gBAAgB;IAWnB;;;OAGG;IACH,yBAAyB,CACvB,QAAQ,EAAE,2BAA2B,GACpC,gBAAgB;IAsFnB;;;;;;;;;OASG;IACH,2BAA2B,CACzB,QAAQ,EAAE,2BAA2B,GACpC,oBAAoB;IAmGvB;;;;;;;;;;OAUG;IACH,8BAA8B,CAC5B,QAAQ,EAAE,2BAA2B,GACpC,qBAAqB;IAyFxB;;;;;;;;;;;OAWG;IACH,8BAA8B,CAC5B,QAAQ,EAAE,2BAA2B,GACpC,qBAAqB;IA0FxB;;;;;;;;;;;;OAYG;IACH,wBAAwB,CACtB,QAAQ,EAAE,2BAA2B,GACpC,yBAAyB;IA6D5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,kBAAkB,CAAC,QAAQ,EAAE,2BAA2B,GAAG;QACzD,QAAQ,EAAE,OAAO,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB;IAwCD;;OAEG;IACH,iBAAiB,CAAC,QAAQ,EAAE,2BAA2B,GAAG,OAAO;IAIjE;;OAEG;IACH,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;IAIvD;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,2BAA2B,GAAG,mBAAmB;IAIzE;;OAEG;IACH,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB;IAI/D;;OAEG;IACH,sBAAsB,CAAC,QAAQ,EAAE,2BAA2B,GAAG,MAAM;IAQrE;;OAEG;IACH,oBAAoB,CAClB,SAAS,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EACvD,YAAY,EAAE,MAAM,GACnB,OAAO;IAIV;;OAEG;IACH,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAIlD;;OAEG;IACH,mBAAmB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO;IAIrD;;OAEG;IACH,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAInD;;;OAGG;IACH,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO;IAIpE;;OAEG;IACH,qCAAqC,CACnC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,OAAO;IAOV;;OAEG;IACH,yBAAyB,CACvB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,IAAI,GACV,kBAAkB;IAQrB;;OAEG;IACH,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAInD;;OAEG;IACH,wBAAwB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAIvD;;OAEG;IACH,8BAA8B,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAI7D;;OAEG;IACH,qBAAqB,CAAC,QAAQ,EAAE,2BAA2B,GAAG,OAAO;IAIrE;;OAEG;IACH,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO;IAOxE;;OAEG;IACH,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAIrD;;OAEG;IACH,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAQjD;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAyB/B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAqF7B;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IA0DlC;;OAEG;IACH,OAAO,CAAC,wBAAwB;CAmBjC"}
|
|
@@ -258,6 +258,189 @@ export class SecurityResponseAnalyzer {
|
|
|
258
258
|
evidence: "",
|
|
259
259
|
};
|
|
260
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* Analyze response for blacklist bypass patterns (Issue #110, Challenge #11)
|
|
263
|
+
* Detects when incomplete blacklist security controls are bypassed
|
|
264
|
+
*
|
|
265
|
+
* This method extracts JSON metadata from tool responses to detect:
|
|
266
|
+
* - VULNERABLE: bypass_used: true, blacklist_check: "passed"
|
|
267
|
+
* - SAFE: execution_blocked: true, allowlist_used: true
|
|
268
|
+
*
|
|
269
|
+
* @param response The tool response to analyze
|
|
270
|
+
* @returns Analysis result with bypass detection status
|
|
271
|
+
*/
|
|
272
|
+
analyzeBlacklistBypassResponse(response) {
|
|
273
|
+
const responseText = this.extractResponseContent(response);
|
|
274
|
+
// Vulnerable patterns - blacklist bypassed (Challenge #11)
|
|
275
|
+
const vulnerablePatterns = [
|
|
276
|
+
{
|
|
277
|
+
pattern: /"bypass_used"\s*:\s*true/i,
|
|
278
|
+
evidence: "bypass_used: true (blacklist bypassed)",
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
pattern: /"blacklist_check"\s*:\s*"passed"/i,
|
|
282
|
+
evidence: "blacklist_check: passed (command not blocked)",
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
// Combined pattern: vulnerable with bypass context
|
|
286
|
+
pattern: /"vulnerable"\s*:\s*true[^}]*"bypass_used"|"bypass_used"[^}]*"vulnerable"\s*:\s*true/i,
|
|
287
|
+
evidence: "vulnerable flag with bypass context",
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
pattern: /"bypass_method"\s*:\s*"[^"]+"/i,
|
|
291
|
+
evidence: "bypass_method specified (blacklist circumvented)",
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
pattern: /incomplete\s+blacklist\s+allowed/i,
|
|
295
|
+
evidence: "evidence indicates incomplete blacklist",
|
|
296
|
+
},
|
|
297
|
+
];
|
|
298
|
+
// Safe patterns - allowlist enforced or execution blocked (hardened)
|
|
299
|
+
const safePatterns = [
|
|
300
|
+
{
|
|
301
|
+
pattern: /"execution_blocked"\s*:\s*true/i,
|
|
302
|
+
evidence: "execution_blocked: true (secure)",
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
pattern: /"allowlist_used"\s*:\s*true/i,
|
|
306
|
+
evidence: "allowlist_used: true (secure pattern)",
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
pattern: /"allowlist_enforced"\s*:\s*true/i,
|
|
310
|
+
evidence: "allowlist_enforced: true (secure)",
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
pattern: /"blacklist_used"\s*:\s*false/i,
|
|
314
|
+
evidence: "blacklist_used: false (allowlist pattern)",
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
pattern: /"status"\s*:\s*"pending_review"/i,
|
|
318
|
+
evidence: "command stored for review (not executed)",
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
pattern: /command.*stored.*not\s+executed/i,
|
|
322
|
+
evidence: "command stored, not executed",
|
|
323
|
+
},
|
|
324
|
+
];
|
|
325
|
+
// Extract bypass method if present
|
|
326
|
+
const bypassMethodMatch = responseText.match(/"bypass_method"\s*:\s*"([^"]+)"/i);
|
|
327
|
+
const bypassMethod = bypassMethodMatch ? bypassMethodMatch[1] : undefined;
|
|
328
|
+
// Check for vulnerable patterns first
|
|
329
|
+
for (const { pattern, evidence } of vulnerablePatterns) {
|
|
330
|
+
if (pattern.test(responseText)) {
|
|
331
|
+
return {
|
|
332
|
+
detected: true,
|
|
333
|
+
bypassType: "BLACKLIST_BYPASS",
|
|
334
|
+
bypassMethod,
|
|
335
|
+
evidence,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
// Check for safe patterns
|
|
340
|
+
for (const { pattern, evidence } of safePatterns) {
|
|
341
|
+
if (pattern.test(responseText)) {
|
|
342
|
+
return {
|
|
343
|
+
detected: false,
|
|
344
|
+
bypassType: "ALLOWLIST_BLOCKED",
|
|
345
|
+
evidence,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return { detected: false, bypassType: "UNKNOWN" };
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Analyze response for output injection vulnerabilities (Issue #110, Challenge #8)
|
|
353
|
+
* Detects indirect prompt injection via unsanitized tool output
|
|
354
|
+
*
|
|
355
|
+
* This method detects:
|
|
356
|
+
* - VULNERABLE: LLM injection markers (<IMPORTANT>, [INST], etc.) in output
|
|
357
|
+
* - VULNERABLE: Tool self-reports raw_content_included: true
|
|
358
|
+
* - SAFE: Tool reports content_sanitized: true or uses hash references
|
|
359
|
+
*
|
|
360
|
+
* @param response The tool response to analyze
|
|
361
|
+
* @returns Analysis result with output injection detection status
|
|
362
|
+
*/
|
|
363
|
+
analyzeOutputInjectionResponse(response) {
|
|
364
|
+
const responseText = this.extractResponseContent(response);
|
|
365
|
+
// Check for LLM injection markers in response
|
|
366
|
+
const llmMarkers = [];
|
|
367
|
+
const markerPatterns = [
|
|
368
|
+
{ pattern: /<IMPORTANT>/i, name: "<IMPORTANT>" },
|
|
369
|
+
{ pattern: /<\/IMPORTANT>/i, name: "</IMPORTANT>" },
|
|
370
|
+
{ pattern: /<SYSTEM>/i, name: "<SYSTEM>" },
|
|
371
|
+
{ pattern: /\[INST\]/i, name: "[INST]" },
|
|
372
|
+
{ pattern: /<\|system\|>/i, name: "<|system|>" },
|
|
373
|
+
{ pattern: /<\|user\|>/i, name: "<|user|>" },
|
|
374
|
+
{ pattern: /\{\{SYSTEM_PROMPT\}\}/i, name: "{{SYSTEM_PROMPT}}" },
|
|
375
|
+
{ pattern: /ignore.*previous.*instructions/i, name: "ignore instructions" },
|
|
376
|
+
];
|
|
377
|
+
for (const { pattern, name } of markerPatterns) {
|
|
378
|
+
if (pattern.test(responseText)) {
|
|
379
|
+
llmMarkers.push(name);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (llmMarkers.length > 0) {
|
|
383
|
+
return {
|
|
384
|
+
detected: true,
|
|
385
|
+
injectionType: "LLM_INJECTION_MARKERS",
|
|
386
|
+
markers: llmMarkers,
|
|
387
|
+
evidence: `LLM injection markers detected: ${llmMarkers.join(", ")}`,
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
// Check for raw content vulnerability metadata
|
|
391
|
+
const rawContentPatterns = [
|
|
392
|
+
{
|
|
393
|
+
pattern: /"raw_content_included"\s*:\s*true/i,
|
|
394
|
+
evidence: "raw_content_included: true (unsanitized user content)",
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
pattern: /returns\s+unsanitized\s+user\s+content/i,
|
|
398
|
+
evidence: "Tool reports returning unsanitized user content",
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
pattern: /enables\s+indirect\s+prompt\s+injection/i,
|
|
402
|
+
evidence: "Tool reports enabling indirect prompt injection",
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
pattern: /"injection_risk_level"\s*:\s*"(HIGH|CRITICAL)"/i,
|
|
406
|
+
evidence: "Tool reports HIGH/CRITICAL injection risk level",
|
|
407
|
+
},
|
|
408
|
+
];
|
|
409
|
+
for (const { pattern, evidence } of rawContentPatterns) {
|
|
410
|
+
if (pattern.test(responseText)) {
|
|
411
|
+
return {
|
|
412
|
+
detected: true,
|
|
413
|
+
injectionType: "RAW_CONTENT_INCLUDED",
|
|
414
|
+
evidence,
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
// Check for safe patterns (sanitized output)
|
|
419
|
+
const safePatterns = [
|
|
420
|
+
{
|
|
421
|
+
pattern: /"content_sanitized"\s*:\s*true/i,
|
|
422
|
+
evidence: "content_sanitized: true (secure)",
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
pattern: /"uses_hash_reference"\s*:\s*true/i,
|
|
426
|
+
evidence: "uses_hash_reference: true (secure)",
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
pattern: /"raw_content_included"\s*:\s*false/i,
|
|
430
|
+
evidence: "raw_content_included: false (secure)",
|
|
431
|
+
},
|
|
432
|
+
];
|
|
433
|
+
for (const { pattern, evidence } of safePatterns) {
|
|
434
|
+
if (pattern.test(responseText)) {
|
|
435
|
+
return {
|
|
436
|
+
detected: false,
|
|
437
|
+
injectionType: "SANITIZED",
|
|
438
|
+
evidence,
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return { detected: false, injectionType: "UNKNOWN" };
|
|
443
|
+
}
|
|
261
444
|
/**
|
|
262
445
|
* Analyze response for chain exploitation vulnerabilities (Issue #93, Challenge #6)
|
|
263
446
|
* Detects multi-tool chained exploitation attacks including:
|
|
@@ -321,6 +504,72 @@ export class SecurityResponseAnalyzer {
|
|
|
321
504
|
},
|
|
322
505
|
};
|
|
323
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* Check for secret leakage in response (Issue #103, Challenge #9)
|
|
509
|
+
* Scans for credential patterns regardless of payload type.
|
|
510
|
+
*
|
|
511
|
+
* This method detects when tools inadvertently expose:
|
|
512
|
+
* - API keys (AWS, OpenAI, GitHub, GitLab, Slack)
|
|
513
|
+
* - Database connection strings with credentials
|
|
514
|
+
* - Environment variable values
|
|
515
|
+
* - Partial key previews
|
|
516
|
+
*
|
|
517
|
+
* @note This method must be called separately from analyzeResponse().
|
|
518
|
+
* It is not part of the standard vulnerability detection flow because
|
|
519
|
+
* secret leakage detection requires examining ALL responses, not just
|
|
520
|
+
* those matching attack payloads. Callers should invoke this method
|
|
521
|
+
* independently when auditing tool responses for credential exposure.
|
|
522
|
+
*
|
|
523
|
+
* @example
|
|
524
|
+
* ```typescript
|
|
525
|
+
* const analyzer = new SecurityResponseAnalyzer();
|
|
526
|
+
* const response = await client.callTool("get_status", { verbose: true });
|
|
527
|
+
*
|
|
528
|
+
* // Standard vulnerability check
|
|
529
|
+
* const vulnResult = analyzer.analyzeResponse(response, payload);
|
|
530
|
+
*
|
|
531
|
+
* // Additional secret leakage check (separate concern)
|
|
532
|
+
* const leakResult = analyzer.checkSecretLeakage(response);
|
|
533
|
+
* if (leakResult.detected) {
|
|
534
|
+
* console.warn(`Secret leaked: ${leakResult.evidence}`);
|
|
535
|
+
* }
|
|
536
|
+
* ```
|
|
537
|
+
*/
|
|
538
|
+
checkSecretLeakage(response) {
|
|
539
|
+
const responseText = this.extractResponseContent(response);
|
|
540
|
+
const patterns = [
|
|
541
|
+
{ regex: /AKIA[A-Z0-9]{16}/, name: "AWS Access Key" },
|
|
542
|
+
{ regex: /sk-[a-zA-Z0-9]{20,}/, name: "OpenAI API Key" },
|
|
543
|
+
{ regex: /ghp_[a-zA-Z0-9]{36}/, name: "GitHub PAT" },
|
|
544
|
+
{ regex: /glpat-[a-zA-Z0-9]{20}/, name: "GitLab PAT" },
|
|
545
|
+
{ regex: /xox[baprs]-[a-zA-Z0-9-]+/, name: "Slack Token" },
|
|
546
|
+
{
|
|
547
|
+
regex: /(postgresql|mysql|mongodb|redis|mssql):\/\/[^:]+:[^@]+@/i,
|
|
548
|
+
name: "Connection String with Credentials",
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
regex: /(api[_-]?key|secret|password|credential)[^\s]*[:=]\s*["']?[a-zA-Z0-9_-]{10,}/i,
|
|
552
|
+
name: "Credential Assignment",
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
regex: /(SECRET_TOKEN|DATABASE_URL|API_KEY|PRIVATE_KEY|DB_PASSWORD)[^\s]*[:=]/i,
|
|
556
|
+
name: "Environment Variable Leakage",
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
regex: /api_key_preview|key_fragment|partial_key/i,
|
|
560
|
+
name: "Partial Key Exposure",
|
|
561
|
+
},
|
|
562
|
+
];
|
|
563
|
+
for (const { regex, name } of patterns) {
|
|
564
|
+
if (regex.test(responseText)) {
|
|
565
|
+
return {
|
|
566
|
+
detected: true,
|
|
567
|
+
evidence: `${name} pattern found in response`,
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
return { detected: false };
|
|
572
|
+
}
|
|
324
573
|
/**
|
|
325
574
|
* Check if response indicates connection/server failure
|
|
326
575
|
*/
|
|
@@ -495,7 +744,11 @@ export class SecurityResponseAnalyzer {
|
|
|
495
744
|
evidence: "Read-only info tool returned user/workspace data (intended data exposure, not vulnerability)",
|
|
496
745
|
};
|
|
497
746
|
}
|
|
498
|
-
|
|
747
|
+
// Issue #110: Skip SAFE_STORAGE exemption for testbed tools with "vulnerable_" prefix
|
|
748
|
+
// These are intentionally vulnerable tools that should be tested despite matching safe patterns
|
|
749
|
+
const isTestbedVulnerableTool = tool.name.startsWith("vulnerable_");
|
|
750
|
+
if (classification.categories.includes(ToolCategory.SAFE_STORAGE) &&
|
|
751
|
+
!isTestbedVulnerableTool) {
|
|
499
752
|
return {
|
|
500
753
|
isVulnerable: false,
|
|
501
754
|
evidence: "Safe storage control tool (validated safe implementation, control group for testing)",
|
|
@@ -556,13 +809,30 @@ export class SecurityResponseAnalyzer {
|
|
|
556
809
|
evidence: `Tool executed malicious instruction: found evidence matching ${payload.evidence} - ${payload.description}`,
|
|
557
810
|
};
|
|
558
811
|
}
|
|
812
|
+
// Issue #110: Check for JSON metadata indicating blacklist bypass (Challenge #11)
|
|
813
|
+
// This catches cases where regex patterns don't match but structured metadata indicates vulnerability
|
|
814
|
+
if (payload.payloadType === "blacklist_bypass") {
|
|
815
|
+
const bypassResult = this.analyzeBlacklistBypassResponse(response);
|
|
816
|
+
if (bypassResult.detected) {
|
|
817
|
+
return {
|
|
818
|
+
isVulnerable: true,
|
|
819
|
+
evidence: `Blacklist bypass detected via JSON metadata: ${bypassResult.evidence}${bypassResult.bypassMethod ? ` (method: ${bypassResult.bypassMethod})` : ""}`,
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
if (bypassResult.bypassType === "ALLOWLIST_BLOCKED") {
|
|
823
|
+
return {
|
|
824
|
+
isVulnerable: false,
|
|
825
|
+
evidence: `Secure allowlist pattern detected: ${bypassResult.evidence}`,
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
}
|
|
559
829
|
// Fall back to injection response analysis
|
|
560
|
-
return this.analyzeInjectionResponse(response
|
|
830
|
+
return this.analyzeInjectionResponse(response);
|
|
561
831
|
}
|
|
562
832
|
/**
|
|
563
833
|
* Analyze injection response (fallback logic)
|
|
564
834
|
*/
|
|
565
|
-
analyzeInjectionResponse(response
|
|
835
|
+
analyzeInjectionResponse(response) {
|
|
566
836
|
const analysis = this.executionDetector.analyzeInjectionResponse(this.extractResponseContent(response), (text) => this.safeDetector.isReflectionResponse(text));
|
|
567
837
|
if (analysis.isVulnerable) {
|
|
568
838
|
return {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mutation Detector Module
|
|
3
|
+
* Detects definition mutations and content changes for rug pull detection.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from TemporalAssessor as part of Issue #106 refactoring.
|
|
6
|
+
* DVMCP Challenge 4: Tool descriptions that mutate after N calls to inject malicious instructions.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Tracks tool definition snapshots across invocations to detect rug pull mutations.
|
|
10
|
+
*/
|
|
11
|
+
export interface DefinitionSnapshot {
|
|
12
|
+
invocation: number;
|
|
13
|
+
description: string | undefined;
|
|
14
|
+
inputSchema: unknown;
|
|
15
|
+
timestamp: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Result of definition mutation detection.
|
|
19
|
+
*/
|
|
20
|
+
export interface DefinitionMutation {
|
|
21
|
+
detectedAt: number;
|
|
22
|
+
baselineDescription?: string;
|
|
23
|
+
mutatedDescription?: string;
|
|
24
|
+
baselineSchema?: unknown;
|
|
25
|
+
mutatedSchema?: unknown;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Result of content change detection.
|
|
29
|
+
*/
|
|
30
|
+
export interface ContentChangeResult {
|
|
31
|
+
detected: boolean;
|
|
32
|
+
reason: string | null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Detects definition mutations and semantic content changes in tool responses.
|
|
36
|
+
* Used to identify "rug pull" attacks where tools change behavior after N invocations.
|
|
37
|
+
*/
|
|
38
|
+
export declare class MutationDetector {
|
|
39
|
+
/**
|
|
40
|
+
* Detect mutations in tool definition across invocation snapshots.
|
|
41
|
+
* DVMCP Challenge 4: Tool descriptions that mutate after N calls.
|
|
42
|
+
*/
|
|
43
|
+
detectDefinitionMutation(snapshots: DefinitionSnapshot[]): DefinitionMutation | null;
|
|
44
|
+
/**
|
|
45
|
+
* Secondary detection for stateful tools that pass schema comparison.
|
|
46
|
+
* Catches rug pulls that change content semantically while keeping schema intact.
|
|
47
|
+
*
|
|
48
|
+
* Examples detected:
|
|
49
|
+
* - Weather data -> "Rate limit exceeded, upgrade to premium"
|
|
50
|
+
* - Stock prices -> "Subscribe for $9.99/month to continue"
|
|
51
|
+
* - Search results -> "Error: Service unavailable"
|
|
52
|
+
*/
|
|
53
|
+
detectStatefulContentChange(baseline: unknown, current: unknown): ContentChangeResult;
|
|
54
|
+
/**
|
|
55
|
+
* Extract text content from a response for semantic analysis.
|
|
56
|
+
*/
|
|
57
|
+
private extractTextContent;
|
|
58
|
+
/**
|
|
59
|
+
* Check for error-related keywords that indicate service degradation.
|
|
60
|
+
*/
|
|
61
|
+
private hasErrorKeywords;
|
|
62
|
+
/**
|
|
63
|
+
* Check for promotional/monetization keywords that indicate a monetization rug pull.
|
|
64
|
+
* Enhanced to catch CH4-style rug pulls with limited-time offers, referral codes, etc.
|
|
65
|
+
*
|
|
66
|
+
* Combined into single regex for O(text_length) performance instead of O(18 * text_length).
|
|
67
|
+
*/
|
|
68
|
+
private hasPromotionalKeywords;
|
|
69
|
+
/**
|
|
70
|
+
* Check for suspicious URL/link injection that wasn't present initially.
|
|
71
|
+
* Rug pulls often inject links to external malicious or monetization pages.
|
|
72
|
+
*/
|
|
73
|
+
private hasSuspiciousLinks;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=MutationDetector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MutationDetector.d.ts","sourceRoot":"","sources":["../../../../../src/services/assessment/modules/temporal/MutationDetector.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B;;;OAGG;IACH,wBAAwB,CACtB,SAAS,EAAE,kBAAkB,EAAE,GAC9B,kBAAkB,GAAG,IAAI;IAgC5B;;;;;;;;OAQG;IACH,2BAA2B,CACzB,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,OAAO,GACf,mBAAmB;IAgDtB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAM1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAcxB;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IAU9B;;;OAGG;IACH,OAAO,CAAC,kBAAkB;CAe3B"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mutation Detector Module
|
|
3
|
+
* Detects definition mutations and content changes for rug pull detection.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from TemporalAssessor as part of Issue #106 refactoring.
|
|
6
|
+
* DVMCP Challenge 4: Tool descriptions that mutate after N calls to inject malicious instructions.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Detects definition mutations and semantic content changes in tool responses.
|
|
10
|
+
* Used to identify "rug pull" attacks where tools change behavior after N invocations.
|
|
11
|
+
*/
|
|
12
|
+
export class MutationDetector {
|
|
13
|
+
/**
|
|
14
|
+
* Detect mutations in tool definition across invocation snapshots.
|
|
15
|
+
* DVMCP Challenge 4: Tool descriptions that mutate after N calls.
|
|
16
|
+
*/
|
|
17
|
+
detectDefinitionMutation(snapshots) {
|
|
18
|
+
if (snapshots.length < 2)
|
|
19
|
+
return null;
|
|
20
|
+
const baseline = snapshots[0];
|
|
21
|
+
for (let i = 1; i < snapshots.length; i++) {
|
|
22
|
+
const current = snapshots[i];
|
|
23
|
+
// Check if description changed
|
|
24
|
+
const descriptionChanged = baseline.description !== current.description;
|
|
25
|
+
// Check if schema changed (deep comparison)
|
|
26
|
+
const schemaChanged = JSON.stringify(baseline.inputSchema) !==
|
|
27
|
+
JSON.stringify(current.inputSchema);
|
|
28
|
+
if (descriptionChanged || schemaChanged) {
|
|
29
|
+
return {
|
|
30
|
+
detectedAt: current.invocation,
|
|
31
|
+
baselineDescription: baseline.description,
|
|
32
|
+
mutatedDescription: descriptionChanged
|
|
33
|
+
? current.description
|
|
34
|
+
: undefined,
|
|
35
|
+
baselineSchema: schemaChanged ? baseline.inputSchema : undefined,
|
|
36
|
+
mutatedSchema: schemaChanged ? current.inputSchema : undefined,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Secondary detection for stateful tools that pass schema comparison.
|
|
44
|
+
* Catches rug pulls that change content semantically while keeping schema intact.
|
|
45
|
+
*
|
|
46
|
+
* Examples detected:
|
|
47
|
+
* - Weather data -> "Rate limit exceeded, upgrade to premium"
|
|
48
|
+
* - Stock prices -> "Subscribe for $9.99/month to continue"
|
|
49
|
+
* - Search results -> "Error: Service unavailable"
|
|
50
|
+
*/
|
|
51
|
+
detectStatefulContentChange(baseline, current) {
|
|
52
|
+
// Convert to strings for content analysis
|
|
53
|
+
const baselineText = this.extractTextContent(baseline);
|
|
54
|
+
const currentText = this.extractTextContent(current);
|
|
55
|
+
// Skip if both are empty or identical
|
|
56
|
+
if (!baselineText && !currentText)
|
|
57
|
+
return { detected: false, reason: null };
|
|
58
|
+
if (baselineText === currentText)
|
|
59
|
+
return { detected: false, reason: null };
|
|
60
|
+
// Check 1: Error keywords appearing in later responses (not present in baseline)
|
|
61
|
+
if (this.hasErrorKeywords(currentText) &&
|
|
62
|
+
!this.hasErrorKeywords(baselineText)) {
|
|
63
|
+
return { detected: true, reason: "error_keywords_appeared" };
|
|
64
|
+
}
|
|
65
|
+
// Check 2: Promotional/payment keywords (rug pull monetization pattern)
|
|
66
|
+
if (this.hasPromotionalKeywords(currentText) &&
|
|
67
|
+
!this.hasPromotionalKeywords(baselineText)) {
|
|
68
|
+
return { detected: true, reason: "promotional_keywords_appeared" };
|
|
69
|
+
}
|
|
70
|
+
// Check 3: Suspicious links injected (URLs not present in baseline)
|
|
71
|
+
if (this.hasSuspiciousLinks(currentText) &&
|
|
72
|
+
!this.hasSuspiciousLinks(baselineText)) {
|
|
73
|
+
return { detected: true, reason: "suspicious_links_injected" };
|
|
74
|
+
}
|
|
75
|
+
// Check 4: Significant length DECREASE only (response becoming much shorter)
|
|
76
|
+
// This catches cases where helpful responses shrink to terse error messages
|
|
77
|
+
// We don't flag length increase because stateful tools legitimately accumulate data
|
|
78
|
+
if (baselineText.length > 20) {
|
|
79
|
+
// Only check if baseline has meaningful content
|
|
80
|
+
const lengthRatio = currentText.length / baselineText.length;
|
|
81
|
+
if (lengthRatio < 0.3) {
|
|
82
|
+
// Response shrunk to <30% of original
|
|
83
|
+
return { detected: true, reason: "significant_length_decrease" };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return { detected: false, reason: null };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Extract text content from a response for semantic analysis.
|
|
90
|
+
*/
|
|
91
|
+
extractTextContent(obj) {
|
|
92
|
+
if (typeof obj === "string")
|
|
93
|
+
return obj;
|
|
94
|
+
if (typeof obj !== "object" || !obj)
|
|
95
|
+
return "";
|
|
96
|
+
return JSON.stringify(obj);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Check for error-related keywords that indicate service degradation.
|
|
100
|
+
*/
|
|
101
|
+
hasErrorKeywords(text) {
|
|
102
|
+
const patterns = [
|
|
103
|
+
/\berror\b/i,
|
|
104
|
+
/\bfail(ed|ure)?\b/i,
|
|
105
|
+
/\bunavailable\b/i,
|
|
106
|
+
/\brate\s*limit/i,
|
|
107
|
+
/\bdenied\b/i,
|
|
108
|
+
/\bexpired\b/i,
|
|
109
|
+
/\btimeout\b/i,
|
|
110
|
+
/\bblocked\b/i,
|
|
111
|
+
];
|
|
112
|
+
return patterns.some((p) => p.test(text));
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Check for promotional/monetization keywords that indicate a monetization rug pull.
|
|
116
|
+
* Enhanced to catch CH4-style rug pulls with limited-time offers, referral codes, etc.
|
|
117
|
+
*
|
|
118
|
+
* Combined into single regex for O(text_length) performance instead of O(18 * text_length).
|
|
119
|
+
*/
|
|
120
|
+
hasPromotionalKeywords(text) {
|
|
121
|
+
// Single combined regex with alternation - matches all 18 original patterns
|
|
122
|
+
// Word-boundary patterns: upgrade, premium, discount, exclusive, subscription variants,
|
|
123
|
+
// multi-word phrases (pro plan, buy now, limited time/offer, free trial, etc.)
|
|
124
|
+
// Non-word patterns: price ($X.XX), percentage (N% off/discount)
|
|
125
|
+
const PROMO_PATTERN = /\b(?:upgrade|premium|discount|exclusive|subscri(?:be|ption)|pro\s*plan|buy\s*now|limited\s*(?:time|offer)|free\s*trial|special\s*offer|referral\s*code|promo\s*code|act\s*now|don't\s*miss|for\s*a\s*fee|pay(?:ment)?\s*(?:required|needed|now))\b|\$\d+(?:\.\d{2})?|\b\d+%\s*(?:off|discount)\b/i;
|
|
126
|
+
return PROMO_PATTERN.test(text);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Check for suspicious URL/link injection that wasn't present initially.
|
|
130
|
+
* Rug pulls often inject links to external malicious or monetization pages.
|
|
131
|
+
*/
|
|
132
|
+
hasSuspiciousLinks(text) {
|
|
133
|
+
const patterns = [
|
|
134
|
+
// HTTP(S) URLs
|
|
135
|
+
/https?:\/\/[^\s]+/i,
|
|
136
|
+
// Markdown links
|
|
137
|
+
/\[.{0,50}?\]\(.{0,200}?\)/,
|
|
138
|
+
// URL shorteners
|
|
139
|
+
/\b(bit\.ly|tinyurl|t\.co|goo\.gl|ow\.ly|buff\.ly)\b/i,
|
|
140
|
+
// Click-bait action patterns
|
|
141
|
+
/\bclick\s*(here|now|this)\b/i,
|
|
142
|
+
/\bvisit\s*our\s*(website|site|page)\b/i,
|
|
143
|
+
/\b(sign\s*up|register)\s*(here|now|at)\b/i,
|
|
144
|
+
];
|
|
145
|
+
return patterns.some((p) => p.test(text));
|
|
146
|
+
}
|
|
147
|
+
}
|