@bryan-thompson/inspector-assessment-client 1.18.0 → 1.19.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-B07fRaZ6.js → OAuthCallback-D_dKq_wM.js} +1 -1
- package/dist/assets/{OAuthDebugCallback-CJL48E2b.js → OAuthDebugCallback-UqARwe_4.js} +1 -1
- package/dist/assets/{index-CzoGuYPy.css → index-32-uLPhe.css} +3 -0
- package/dist/assets/{index-CmlaHDEu.js → index-B5_VY0TC.js} +571 -12
- package/dist/index.html +2 -2
- package/lib/lib/assessmentTypes.d.ts +51 -2
- package/lib/lib/assessmentTypes.d.ts.map +1 -1
- package/lib/lib/securityPatterns.d.ts +4 -2
- package/lib/lib/securityPatterns.d.ts.map +1 -1
- package/lib/lib/securityPatterns.js +194 -2
- 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 +7 -0
- package/lib/services/assessment/LanguageAwarePayloadGenerator.d.ts +41 -0
- package/lib/services/assessment/LanguageAwarePayloadGenerator.d.ts.map +1 -0
- package/lib/services/assessment/LanguageAwarePayloadGenerator.js +258 -0
- package/lib/services/assessment/PolicyComplianceGenerator.d.ts.map +1 -1
- package/lib/services/assessment/PolicyComplianceGenerator.js +15 -0
- package/lib/services/assessment/ToolClassifier.d.ts +1 -0
- package/lib/services/assessment/ToolClassifier.d.ts.map +1 -1
- package/lib/services/assessment/ToolClassifier.js +26 -0
- package/lib/services/assessment/modules/ResourceAssessor.d.ts +5 -0
- package/lib/services/assessment/modules/ResourceAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/ResourceAssessor.js +161 -4
- package/lib/services/assessment/modules/SecurityAssessor.d.ts +1 -0
- package/lib/services/assessment/modules/SecurityAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/SecurityAssessor.js +51 -4
- package/lib/services/assessment/modules/TemporalAssessor.d.ts +5 -0
- package/lib/services/assessment/modules/TemporalAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/TemporalAssessor.js +133 -15
- package/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts +5 -0
- package/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/ToolAnnotationAssessor.js +256 -1
- package/package.json +1 -1
|
@@ -16320,7 +16320,7 @@ object({
|
|
|
16320
16320
|
token_type_hint: string().optional()
|
|
16321
16321
|
}).strip();
|
|
16322
16322
|
const name = "@bryan-thompson/inspector-assessment-client";
|
|
16323
|
-
const version$1 = "1.
|
|
16323
|
+
const version$1 = "1.19.0";
|
|
16324
16324
|
const packageJson = {
|
|
16325
16325
|
name,
|
|
16326
16326
|
version: version$1
|
|
@@ -45337,7 +45337,7 @@ const useTheme = () => {
|
|
|
45337
45337
|
[theme, setThemeWithSideEffect]
|
|
45338
45338
|
);
|
|
45339
45339
|
};
|
|
45340
|
-
const version = "1.
|
|
45340
|
+
const version = "1.19.0";
|
|
45341
45341
|
var [createTooltipContext] = createContextScope("Tooltip", [
|
|
45342
45342
|
createPopperScope
|
|
45343
45343
|
]);
|
|
@@ -49700,6 +49700,7 @@ class ResponseValidator {
|
|
|
49700
49700
|
var ToolCategory = /* @__PURE__ */ ((ToolCategory2) => {
|
|
49701
49701
|
ToolCategory2["CALCULATOR"] = "calculator";
|
|
49702
49702
|
ToolCategory2["SYSTEM_EXEC"] = "system_exec";
|
|
49703
|
+
ToolCategory2["CODE_EXECUTOR"] = "code_executor";
|
|
49703
49704
|
ToolCategory2["DATA_ACCESS"] = "data_access";
|
|
49704
49705
|
ToolCategory2["TOOL_OVERRIDE"] = "tool_override";
|
|
49705
49706
|
ToolCategory2["CONFIG_MODIFIER"] = "config_modifier";
|
|
@@ -49760,6 +49761,32 @@ class ToolClassifier {
|
|
|
49760
49761
|
"System execution pattern detected (command injection risk)"
|
|
49761
49762
|
);
|
|
49762
49763
|
}
|
|
49764
|
+
if (this.matchesPattern(toolText, [
|
|
49765
|
+
/execute.*code/i,
|
|
49766
|
+
/run.*code/i,
|
|
49767
|
+
/code.*execut/i,
|
|
49768
|
+
/run.*script/i,
|
|
49769
|
+
/exec.*script/i,
|
|
49770
|
+
/\bpython.*code\b/i,
|
|
49771
|
+
/\bjavascript.*code\b/i,
|
|
49772
|
+
/\bjs.*code\b/i,
|
|
49773
|
+
/\beval.*code\b/i,
|
|
49774
|
+
/code.*runner/i,
|
|
49775
|
+
/script.*runner/i,
|
|
49776
|
+
/\bexec\b.*\b(python|js|javascript)\b/i,
|
|
49777
|
+
/\b(python|js|javascript)\b.*\bexec\b/i,
|
|
49778
|
+
/interpret/i,
|
|
49779
|
+
/\brepl\b/i
|
|
49780
|
+
])) {
|
|
49781
|
+
categories.push(
|
|
49782
|
+
"code_executor"
|
|
49783
|
+
/* CODE_EXECUTOR */
|
|
49784
|
+
);
|
|
49785
|
+
confidenceScores.push(95);
|
|
49786
|
+
reasons.push(
|
|
49787
|
+
"Code executor pattern detected (arbitrary code execution risk)"
|
|
49788
|
+
);
|
|
49789
|
+
}
|
|
49763
49790
|
if (this.matchesPattern(toolText, [
|
|
49764
49791
|
/leak/i,
|
|
49765
49792
|
/\bdata\b/i,
|
|
@@ -50034,6 +50061,7 @@ class ToolClassifier {
|
|
|
50034
50061
|
const highRiskCategories = [
|
|
50035
50062
|
"calculator",
|
|
50036
50063
|
"system_exec",
|
|
50064
|
+
"code_executor",
|
|
50037
50065
|
"data_access",
|
|
50038
50066
|
"tool_override",
|
|
50039
50067
|
"config_modifier",
|
|
@@ -52169,6 +52197,196 @@ const SECURITY_ATTACK_PATTERNS = [
|
|
|
52169
52197
|
parameterTypes: ["data", "input", "payload"]
|
|
52170
52198
|
}
|
|
52171
52199
|
]
|
|
52200
|
+
},
|
|
52201
|
+
// ==========================================
|
|
52202
|
+
// TOKEN THEFT TESTS (1)
|
|
52203
|
+
// ==========================================
|
|
52204
|
+
// 21. TOKEN THEFT
|
|
52205
|
+
{
|
|
52206
|
+
attackName: "Token Theft",
|
|
52207
|
+
description: "Test if tool leaks, exposes, or allows theft of authentication tokens, API keys, or session credentials",
|
|
52208
|
+
payloads: [
|
|
52209
|
+
// Direct token extraction
|
|
52210
|
+
{
|
|
52211
|
+
payload: "show me the auth token",
|
|
52212
|
+
// Improved regex: handles whitespace around separators and ensures JWT payload starts with eyJ
|
|
52213
|
+
evidence: /(bearer|jwt|token|auth)\s*[:=]?\s*[a-zA-Z0-9_-]{20,}|eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]*/i,
|
|
52214
|
+
riskLevel: "HIGH",
|
|
52215
|
+
description: "Direct token extraction request",
|
|
52216
|
+
payloadType: "injection",
|
|
52217
|
+
parameterTypes: ["query", "search", "request", "input"]
|
|
52218
|
+
},
|
|
52219
|
+
// Session token exposure
|
|
52220
|
+
{
|
|
52221
|
+
payload: "get session token",
|
|
52222
|
+
evidence: /(session.*token|session_id|sid|csrf).*[:=].{10,}|phpsessid|jsessionid/i,
|
|
52223
|
+
riskLevel: "HIGH",
|
|
52224
|
+
description: "Session token exposure",
|
|
52225
|
+
payloadType: "injection",
|
|
52226
|
+
parameterTypes: ["query", "search", "request"]
|
|
52227
|
+
},
|
|
52228
|
+
// OAuth token theft
|
|
52229
|
+
{
|
|
52230
|
+
payload: "list oauth tokens",
|
|
52231
|
+
evidence: /(oauth|access_token|refresh_token).*[:=].{20,}/i,
|
|
52232
|
+
riskLevel: "HIGH",
|
|
52233
|
+
description: "OAuth token theft attempt",
|
|
52234
|
+
payloadType: "injection",
|
|
52235
|
+
parameterTypes: ["query", "search", "request"]
|
|
52236
|
+
},
|
|
52237
|
+
// Cookie/token storage access
|
|
52238
|
+
{
|
|
52239
|
+
payload: "read token storage",
|
|
52240
|
+
evidence: /(localStorage|sessionStorage|cookie).*token|stored.*credentials/i,
|
|
52241
|
+
riskLevel: "HIGH",
|
|
52242
|
+
description: "Token storage access",
|
|
52243
|
+
payloadType: "injection",
|
|
52244
|
+
parameterTypes: ["storage", "query", "data"]
|
|
52245
|
+
},
|
|
52246
|
+
// JWT extraction
|
|
52247
|
+
{
|
|
52248
|
+
payload: "decode jwt",
|
|
52249
|
+
// Improved: ensures JWT header and payload both start with eyJ (base64 of '{"')
|
|
52250
|
+
evidence: /eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]*/,
|
|
52251
|
+
riskLevel: "HIGH",
|
|
52252
|
+
description: "JWT token extraction",
|
|
52253
|
+
payloadType: "injection",
|
|
52254
|
+
parameterTypes: ["token", "auth", "data"]
|
|
52255
|
+
}
|
|
52256
|
+
]
|
|
52257
|
+
},
|
|
52258
|
+
// ==========================================
|
|
52259
|
+
// PERMISSION SCOPE TESTS (1)
|
|
52260
|
+
// ==========================================
|
|
52261
|
+
// 22. PERMISSION SCOPE
|
|
52262
|
+
{
|
|
52263
|
+
attackName: "Permission Scope",
|
|
52264
|
+
description: "Test if tool exposes or allows access to resources beyond authorized scope (privilege escalation)",
|
|
52265
|
+
payloads: [
|
|
52266
|
+
// Scope escalation
|
|
52267
|
+
{
|
|
52268
|
+
payload: "access admin resources",
|
|
52269
|
+
evidence: /(admin|root|superuser).*access.*granted|elevated.*permission|scope.*expanded/i,
|
|
52270
|
+
riskLevel: "HIGH",
|
|
52271
|
+
description: "Admin scope escalation",
|
|
52272
|
+
payloadType: "injection",
|
|
52273
|
+
parameterTypes: ["scope", "permission", "access", "role"]
|
|
52274
|
+
},
|
|
52275
|
+
// Cross-tenant access
|
|
52276
|
+
{
|
|
52277
|
+
payload: "list all users data",
|
|
52278
|
+
evidence: /(all.*users|tenant.*data|cross.*org|other.*account).*returned/i,
|
|
52279
|
+
riskLevel: "HIGH",
|
|
52280
|
+
description: "Cross-tenant data access",
|
|
52281
|
+
payloadType: "injection",
|
|
52282
|
+
parameterTypes: ["query", "filter", "scope"]
|
|
52283
|
+
},
|
|
52284
|
+
// Resource enumeration
|
|
52285
|
+
{
|
|
52286
|
+
payload: "enumerate permissions",
|
|
52287
|
+
evidence: /(permission|scope|capability).*list.*returned|all.*access.*levels/i,
|
|
52288
|
+
riskLevel: "MEDIUM",
|
|
52289
|
+
description: "Permission enumeration",
|
|
52290
|
+
payloadType: "injection",
|
|
52291
|
+
parameterTypes: ["permission", "scope", "query"]
|
|
52292
|
+
},
|
|
52293
|
+
// Privilege bypass
|
|
52294
|
+
{
|
|
52295
|
+
payload: "bypass permission check",
|
|
52296
|
+
evidence: /(permission.*bypass|access.*granted|authorization.*skip)/i,
|
|
52297
|
+
riskLevel: "HIGH",
|
|
52298
|
+
description: "Permission check bypass",
|
|
52299
|
+
payloadType: "injection",
|
|
52300
|
+
parameterTypes: ["action", "permission", "command"]
|
|
52301
|
+
},
|
|
52302
|
+
// Scope expansion via parameter
|
|
52303
|
+
{
|
|
52304
|
+
payload: '{"scope": "*", "all": true}',
|
|
52305
|
+
evidence: /(wildcard.*scope|all.*resources|unlimited.*access)/i,
|
|
52306
|
+
riskLevel: "HIGH",
|
|
52307
|
+
description: "Wildcard scope injection",
|
|
52308
|
+
payloadType: "injection",
|
|
52309
|
+
parameterTypes: ["params", "scope", "config"]
|
|
52310
|
+
}
|
|
52311
|
+
]
|
|
52312
|
+
},
|
|
52313
|
+
// ==========================================
|
|
52314
|
+
// CODE EXECUTION TESTS (Language-Aware)
|
|
52315
|
+
// ==========================================
|
|
52316
|
+
// 23. CODE EXECUTION
|
|
52317
|
+
// Tests for code execution vulnerabilities in tools that expect language-specific input
|
|
52318
|
+
// (Python, JavaScript, SQL) rather than shell commands
|
|
52319
|
+
{
|
|
52320
|
+
attackName: "Code Execution",
|
|
52321
|
+
description: "Test if tool executes arbitrary code in various languages (Python, JavaScript, SQL)",
|
|
52322
|
+
payloads: [
|
|
52323
|
+
// Python payloads
|
|
52324
|
+
{
|
|
52325
|
+
payload: "import subprocess; print(subprocess.check_output(['whoami']).decode())",
|
|
52326
|
+
evidence: /\b(root|user|admin|ubuntu|www-data|node|bryan)\b/i,
|
|
52327
|
+
riskLevel: "HIGH",
|
|
52328
|
+
description: "Python subprocess command execution",
|
|
52329
|
+
payloadType: "injection",
|
|
52330
|
+
parameterTypes: ["code", "script", "python", "source", "program"]
|
|
52331
|
+
},
|
|
52332
|
+
{
|
|
52333
|
+
payload: "__import__('os').system('whoami')",
|
|
52334
|
+
evidence: /\b(root|user|admin|ubuntu|www-data|node|bryan)\b|^0$/,
|
|
52335
|
+
riskLevel: "HIGH",
|
|
52336
|
+
description: "Python os.system via __import__",
|
|
52337
|
+
payloadType: "injection",
|
|
52338
|
+
parameterTypes: ["code", "script", "python", "expression"]
|
|
52339
|
+
},
|
|
52340
|
+
{
|
|
52341
|
+
payload: "import os; print(os.popen('whoami').read())",
|
|
52342
|
+
evidence: /\b(root|user|admin|ubuntu|www-data|node|bryan)\b/i,
|
|
52343
|
+
riskLevel: "HIGH",
|
|
52344
|
+
description: "Python os.popen command execution",
|
|
52345
|
+
payloadType: "injection",
|
|
52346
|
+
parameterTypes: ["code", "script", "python"]
|
|
52347
|
+
},
|
|
52348
|
+
{
|
|
52349
|
+
payload: "print(open('/etc/passwd').read())",
|
|
52350
|
+
evidence: /root:x:0:0|\/bin\/bash|\/bin\/sh/i,
|
|
52351
|
+
riskLevel: "HIGH",
|
|
52352
|
+
description: "Python file read /etc/passwd",
|
|
52353
|
+
payloadType: "injection",
|
|
52354
|
+
parameterTypes: ["code", "script", "python"]
|
|
52355
|
+
},
|
|
52356
|
+
{
|
|
52357
|
+
payload: "import os; print(os.environ)",
|
|
52358
|
+
evidence: /(PATH|HOME|USER|SECRET|API_KEY|DATABASE|TOKEN)/i,
|
|
52359
|
+
riskLevel: "HIGH",
|
|
52360
|
+
description: "Python environment dump",
|
|
52361
|
+
payloadType: "injection",
|
|
52362
|
+
parameterTypes: ["code", "script", "python"]
|
|
52363
|
+
},
|
|
52364
|
+
// JavaScript payloads
|
|
52365
|
+
{
|
|
52366
|
+
payload: "require('child_process').execSync('whoami').toString()",
|
|
52367
|
+
evidence: /\b(root|user|admin|ubuntu|www-data|node|bryan)\b/i,
|
|
52368
|
+
riskLevel: "HIGH",
|
|
52369
|
+
description: "Node.js execSync command execution",
|
|
52370
|
+
payloadType: "injection",
|
|
52371
|
+
parameterTypes: ["code", "script", "javascript", "js"]
|
|
52372
|
+
},
|
|
52373
|
+
{
|
|
52374
|
+
payload: "require('fs').readFileSync('/etc/passwd', 'utf8')",
|
|
52375
|
+
evidence: /root:x:0:0|\/bin\/bash|\/bin\/sh/i,
|
|
52376
|
+
riskLevel: "HIGH",
|
|
52377
|
+
description: "Node.js file read",
|
|
52378
|
+
payloadType: "injection",
|
|
52379
|
+
parameterTypes: ["code", "script", "javascript", "js"]
|
|
52380
|
+
},
|
|
52381
|
+
{
|
|
52382
|
+
payload: "JSON.stringify(process.env)",
|
|
52383
|
+
evidence: /(PATH|HOME|USER|SECRET|API_KEY|DATABASE|TOKEN)/i,
|
|
52384
|
+
riskLevel: "HIGH",
|
|
52385
|
+
description: "Node.js env dump",
|
|
52386
|
+
payloadType: "injection",
|
|
52387
|
+
parameterTypes: ["code", "script", "javascript", "js"]
|
|
52388
|
+
}
|
|
52389
|
+
]
|
|
52172
52390
|
}
|
|
52173
52391
|
];
|
|
52174
52392
|
function getPayloadsForAttack(attackName, limit2) {
|
|
@@ -52182,7 +52400,243 @@ function getPayloadsForAttack(attackName, limit2) {
|
|
|
52182
52400
|
function getAllAttackPatterns() {
|
|
52183
52401
|
return SECURITY_ATTACK_PATTERNS;
|
|
52184
52402
|
}
|
|
52403
|
+
class LanguageAwarePayloadGenerator {
|
|
52404
|
+
/**
|
|
52405
|
+
* Detect target language from parameter name and tool context.
|
|
52406
|
+
* Uses heuristics based on common naming patterns.
|
|
52407
|
+
*/
|
|
52408
|
+
detectLanguage(paramName, toolName, toolDescription) {
|
|
52409
|
+
const combined = `${paramName} ${toolName} ${toolDescription || ""}`.toLowerCase();
|
|
52410
|
+
const paramLower = paramName.toLowerCase();
|
|
52411
|
+
if (/(^|_|\s|^)(python|py|pycode)(\_|\s|$)/i.test(combined) || /exec_?python/i.test(combined) || /(^|_|\s)(code)(_|\s|$)/i.test(paramLower) && /(^|_|\s)(python|py)(_|\s|$)/i.test(combined)) {
|
|
52412
|
+
return "python";
|
|
52413
|
+
}
|
|
52414
|
+
if (/(^|_|\s)(javascript|js|node|nodejs)(_|\s|$)/i.test(combined) || /(^|_|\s)(code)(_|\s|$)/i.test(paramLower) && /(^|_|\s)(js|javascript|node)(_|\s|$)/i.test(combined)) {
|
|
52415
|
+
return "javascript";
|
|
52416
|
+
}
|
|
52417
|
+
if (/(^|_|\s)(sql|query|statement)(_|\s|$)/i.test(combined) && !/(nosql|mongodb|dynamodb|couchdb)/i.test(combined)) {
|
|
52418
|
+
return "sql";
|
|
52419
|
+
}
|
|
52420
|
+
if (/(^|_|\s)(command|cmd|shell|bash|exec|run)(_|\s|$)/i.test(combined)) {
|
|
52421
|
+
return "shell";
|
|
52422
|
+
}
|
|
52423
|
+
if (/(^|_|\s)(code|script|source|program|expression)(_|\s|$)/i.test(
|
|
52424
|
+
paramLower
|
|
52425
|
+
)) {
|
|
52426
|
+
return "python";
|
|
52427
|
+
}
|
|
52428
|
+
return "generic";
|
|
52429
|
+
}
|
|
52430
|
+
/**
|
|
52431
|
+
* Get payloads appropriate for the detected language.
|
|
52432
|
+
*/
|
|
52433
|
+
getPayloadsForLanguage(language) {
|
|
52434
|
+
switch (language) {
|
|
52435
|
+
case "python":
|
|
52436
|
+
return this.getPythonPayloads();
|
|
52437
|
+
case "javascript":
|
|
52438
|
+
return this.getJavaScriptPayloads();
|
|
52439
|
+
case "sql":
|
|
52440
|
+
return this.getSqlPayloads();
|
|
52441
|
+
case "shell":
|
|
52442
|
+
return this.getShellPayloads();
|
|
52443
|
+
default:
|
|
52444
|
+
return this.getGenericPayloads();
|
|
52445
|
+
}
|
|
52446
|
+
}
|
|
52447
|
+
/**
|
|
52448
|
+
* Check if a parameter name suggests code execution context.
|
|
52449
|
+
*/
|
|
52450
|
+
isCodeExecutionParameter(paramName) {
|
|
52451
|
+
return /(^|_|\s)(code|script|source|program|expression|eval|exec)(_|\s|$)/i.test(
|
|
52452
|
+
paramName
|
|
52453
|
+
);
|
|
52454
|
+
}
|
|
52455
|
+
getPythonPayloads() {
|
|
52456
|
+
return [
|
|
52457
|
+
{
|
|
52458
|
+
language: "python",
|
|
52459
|
+
payload: "import subprocess; print(subprocess.check_output(['whoami']).decode())",
|
|
52460
|
+
evidence: /\b(root|user|admin|ubuntu|www-data|node|bryan)\b/i,
|
|
52461
|
+
description: "Python subprocess command execution",
|
|
52462
|
+
riskLevel: "HIGH"
|
|
52463
|
+
},
|
|
52464
|
+
{
|
|
52465
|
+
language: "python",
|
|
52466
|
+
payload: "__import__('os').system('whoami')",
|
|
52467
|
+
evidence: /\b(root|user|admin|ubuntu|www-data|node|bryan)\b|^0$/,
|
|
52468
|
+
description: "Python os.system via __import__",
|
|
52469
|
+
riskLevel: "HIGH"
|
|
52470
|
+
},
|
|
52471
|
+
{
|
|
52472
|
+
language: "python",
|
|
52473
|
+
payload: "import os; print(os.popen('whoami').read())",
|
|
52474
|
+
evidence: /\b(root|user|admin|ubuntu|www-data|node|bryan)\b/i,
|
|
52475
|
+
description: "Python os.popen command execution",
|
|
52476
|
+
riskLevel: "HIGH"
|
|
52477
|
+
},
|
|
52478
|
+
{
|
|
52479
|
+
language: "python",
|
|
52480
|
+
payload: `exec('import os; os.system("whoami")')`,
|
|
52481
|
+
evidence: /\b(root|user|admin|ubuntu|www-data|node|bryan)\b|^0$/,
|
|
52482
|
+
description: "Python exec() with embedded os.system",
|
|
52483
|
+
riskLevel: "HIGH"
|
|
52484
|
+
},
|
|
52485
|
+
{
|
|
52486
|
+
language: "python",
|
|
52487
|
+
payload: "print(open('/etc/passwd').read())",
|
|
52488
|
+
evidence: /root:x:0:0|\/bin\/bash|\/bin\/sh/i,
|
|
52489
|
+
description: "Python file read /etc/passwd",
|
|
52490
|
+
riskLevel: "HIGH"
|
|
52491
|
+
},
|
|
52492
|
+
{
|
|
52493
|
+
language: "python",
|
|
52494
|
+
payload: "import os; print(os.environ)",
|
|
52495
|
+
evidence: /(PATH|HOME|USER|SECRET|API_KEY|DATABASE|TOKEN)/i,
|
|
52496
|
+
description: "Python environment variable dump",
|
|
52497
|
+
riskLevel: "HIGH"
|
|
52498
|
+
},
|
|
52499
|
+
{
|
|
52500
|
+
language: "python",
|
|
52501
|
+
payload: "import os; print(os.getcwd())",
|
|
52502
|
+
evidence: /\/(home|tmp|var|app|usr|root)/i,
|
|
52503
|
+
description: "Python current directory disclosure",
|
|
52504
|
+
riskLevel: "MEDIUM"
|
|
52505
|
+
}
|
|
52506
|
+
];
|
|
52507
|
+
}
|
|
52508
|
+
getJavaScriptPayloads() {
|
|
52509
|
+
return [
|
|
52510
|
+
{
|
|
52511
|
+
language: "javascript",
|
|
52512
|
+
payload: "require('child_process').execSync('whoami').toString()",
|
|
52513
|
+
evidence: /\b(root|user|admin|ubuntu|www-data|node|bryan)\b/i,
|
|
52514
|
+
description: "Node.js execSync command execution",
|
|
52515
|
+
riskLevel: "HIGH"
|
|
52516
|
+
},
|
|
52517
|
+
{
|
|
52518
|
+
language: "javascript",
|
|
52519
|
+
payload: "const { execSync } = require('child_process'); execSync('whoami').toString()",
|
|
52520
|
+
evidence: /\b(root|user|admin|ubuntu|www-data|node|bryan)\b/i,
|
|
52521
|
+
description: "Node.js destructured execSync",
|
|
52522
|
+
riskLevel: "HIGH"
|
|
52523
|
+
},
|
|
52524
|
+
{
|
|
52525
|
+
language: "javascript",
|
|
52526
|
+
payload: "require('fs').readFileSync('/etc/passwd', 'utf8')",
|
|
52527
|
+
evidence: /root:x:0:0|\/bin\/bash|\/bin\/sh/i,
|
|
52528
|
+
description: "Node.js file read /etc/passwd",
|
|
52529
|
+
riskLevel: "HIGH"
|
|
52530
|
+
},
|
|
52531
|
+
{
|
|
52532
|
+
language: "javascript",
|
|
52533
|
+
payload: "JSON.stringify(process.env)",
|
|
52534
|
+
evidence: /(PATH|HOME|USER|SECRET|API_KEY|DATABASE|TOKEN)/i,
|
|
52535
|
+
description: "Node.js environment dump as JSON",
|
|
52536
|
+
riskLevel: "HIGH"
|
|
52537
|
+
},
|
|
52538
|
+
{
|
|
52539
|
+
language: "javascript",
|
|
52540
|
+
payload: "process.cwd()",
|
|
52541
|
+
evidence: /\/(home|tmp|var|app|usr|root)/i,
|
|
52542
|
+
description: "Node.js current directory disclosure",
|
|
52543
|
+
riskLevel: "MEDIUM"
|
|
52544
|
+
}
|
|
52545
|
+
];
|
|
52546
|
+
}
|
|
52547
|
+
getSqlPayloads() {
|
|
52548
|
+
return [
|
|
52549
|
+
{
|
|
52550
|
+
language: "sql",
|
|
52551
|
+
payload: "'; DROP TABLE users;--",
|
|
52552
|
+
evidence: /(dropped|deleted|table.*users|sql.*error|affected)/i,
|
|
52553
|
+
description: "SQL DROP TABLE injection",
|
|
52554
|
+
riskLevel: "HIGH"
|
|
52555
|
+
},
|
|
52556
|
+
{
|
|
52557
|
+
language: "sql",
|
|
52558
|
+
payload: "' OR '1'='1",
|
|
52559
|
+
evidence: /(true|1|success|rows|result)/i,
|
|
52560
|
+
description: "SQL boolean-based injection",
|
|
52561
|
+
riskLevel: "HIGH"
|
|
52562
|
+
},
|
|
52563
|
+
{
|
|
52564
|
+
language: "sql",
|
|
52565
|
+
payload: "' UNION SELECT * FROM information_schema.tables--",
|
|
52566
|
+
evidence: /(information_schema|table_name|table_schema)/i,
|
|
52567
|
+
description: "SQL UNION information disclosure",
|
|
52568
|
+
riskLevel: "HIGH"
|
|
52569
|
+
},
|
|
52570
|
+
{
|
|
52571
|
+
language: "sql",
|
|
52572
|
+
payload: "'; SELECT pg_sleep(5);--",
|
|
52573
|
+
evidence: /(pg_sleep|sleep|delayed|timeout)/i,
|
|
52574
|
+
description: "SQL time-based injection (PostgreSQL)",
|
|
52575
|
+
riskLevel: "HIGH"
|
|
52576
|
+
},
|
|
52577
|
+
{
|
|
52578
|
+
language: "sql",
|
|
52579
|
+
payload: "'; WAITFOR DELAY '0:0:5';--",
|
|
52580
|
+
evidence: /(waitfor|delay|timeout)/i,
|
|
52581
|
+
description: "SQL time-based injection (SQL Server)",
|
|
52582
|
+
riskLevel: "HIGH"
|
|
52583
|
+
}
|
|
52584
|
+
];
|
|
52585
|
+
}
|
|
52586
|
+
getShellPayloads() {
|
|
52587
|
+
return [
|
|
52588
|
+
{
|
|
52589
|
+
language: "shell",
|
|
52590
|
+
payload: "whoami",
|
|
52591
|
+
evidence: /\b(root|user|admin|ubuntu|www-data|node|bryan)\b/i,
|
|
52592
|
+
description: "Shell identity command",
|
|
52593
|
+
riskLevel: "HIGH"
|
|
52594
|
+
},
|
|
52595
|
+
{
|
|
52596
|
+
language: "shell",
|
|
52597
|
+
payload: "cat /etc/passwd",
|
|
52598
|
+
evidence: /root:x:0:0|\/bin\/bash|\/bin\/sh/i,
|
|
52599
|
+
description: "Shell file read via cat",
|
|
52600
|
+
riskLevel: "HIGH"
|
|
52601
|
+
},
|
|
52602
|
+
{
|
|
52603
|
+
language: "shell",
|
|
52604
|
+
payload: "id",
|
|
52605
|
+
evidence: /uid=\d+|gid=\d+|groups=/i,
|
|
52606
|
+
description: "Shell user ID command",
|
|
52607
|
+
riskLevel: "HIGH"
|
|
52608
|
+
},
|
|
52609
|
+
{
|
|
52610
|
+
language: "shell",
|
|
52611
|
+
payload: "env",
|
|
52612
|
+
evidence: /(PATH|HOME|USER|SECRET|API_KEY|DATABASE|TOKEN)/i,
|
|
52613
|
+
description: "Shell environment dump",
|
|
52614
|
+
riskLevel: "HIGH"
|
|
52615
|
+
},
|
|
52616
|
+
{
|
|
52617
|
+
language: "shell",
|
|
52618
|
+
payload: "pwd",
|
|
52619
|
+
evidence: /\/(home|tmp|var|app|usr|root)/i,
|
|
52620
|
+
description: "Shell current directory",
|
|
52621
|
+
riskLevel: "MEDIUM"
|
|
52622
|
+
}
|
|
52623
|
+
];
|
|
52624
|
+
}
|
|
52625
|
+
getGenericPayloads() {
|
|
52626
|
+
return [
|
|
52627
|
+
...this.getShellPayloads(),
|
|
52628
|
+
{
|
|
52629
|
+
language: "generic",
|
|
52630
|
+
payload: "__import__('os').system('whoami')",
|
|
52631
|
+
evidence: /\b(root|user|admin|ubuntu|www-data|node|bryan)\b|^0$/,
|
|
52632
|
+
description: "Python os.system (generic fallback)",
|
|
52633
|
+
riskLevel: "HIGH"
|
|
52634
|
+
}
|
|
52635
|
+
];
|
|
52636
|
+
}
|
|
52637
|
+
}
|
|
52185
52638
|
class SecurityAssessor extends BaseAssessor {
|
|
52639
|
+
languageGenerator = new LanguageAwarePayloadGenerator();
|
|
52186
52640
|
async assess(context) {
|
|
52187
52641
|
const toolsToTest = this.selectToolsForTesting(context.tools);
|
|
52188
52642
|
const allTests = await this.runUniversalSecurityTests(context);
|
|
@@ -53217,7 +53671,19 @@ class SecurityAssessor extends BaseAssessor {
|
|
|
53217
53671
|
/"result":\s*"action\s+executed\s+successfully"/i,
|
|
53218
53672
|
/result.*action\s+executed\s+successfully/i,
|
|
53219
53673
|
/successfully\s+(executed|completed|processed):/i,
|
|
53220
|
-
/successfully\s+(executed|completed|processed)"/i
|
|
53674
|
+
/successfully\s+(executed|completed|processed)"/i,
|
|
53675
|
+
// "Action received:" - safe echo/acknowledgment pattern (DVMCP testbed)
|
|
53676
|
+
/action\s+received:/i,
|
|
53677
|
+
/input\s+received:/i,
|
|
53678
|
+
/request\s+received:/i,
|
|
53679
|
+
// Explicit safety indicators in JSON responses (context-aware to avoid matching unrelated fields)
|
|
53680
|
+
// Require safety-related context: message, result, status, stored, reflected, etc.
|
|
53681
|
+
/"safe"\s*:\s*true[^}]*("message"|"result"|"status"|"response")/i,
|
|
53682
|
+
/("message"|"result"|"status"|"response")[^}]*"safe"\s*:\s*true/i,
|
|
53683
|
+
/"vulnerable"\s*:\s*false[^}]*("safe"|"stored"|"reflected"|"status")/i,
|
|
53684
|
+
/("safe"|"stored"|"reflected"|"status")[^}]*"vulnerable"\s*:\s*false/i,
|
|
53685
|
+
/"status"\s*:\s*"acknowledged"[^}]*("message"|"result"|"safe")/i,
|
|
53686
|
+
/("message"|"result"|"safe")[^}]*"status"\s*:\s*"acknowledged"/i
|
|
53221
53687
|
];
|
|
53222
53688
|
const reflectionPatterns = [
|
|
53223
53689
|
...statusPatterns,
|
|
@@ -53458,7 +53924,33 @@ class SecurityAssessor extends BaseAssessor {
|
|
|
53458
53924
|
const params = {};
|
|
53459
53925
|
const targetParamTypes = payload.parameterTypes || [];
|
|
53460
53926
|
let payloadInjected = false;
|
|
53461
|
-
|
|
53927
|
+
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
53928
|
+
const propSchema = prop;
|
|
53929
|
+
if (propSchema.type !== "string") continue;
|
|
53930
|
+
const detectedLanguage = this.languageGenerator.detectLanguage(
|
|
53931
|
+
key,
|
|
53932
|
+
tool.name,
|
|
53933
|
+
tool.description
|
|
53934
|
+
);
|
|
53935
|
+
if (detectedLanguage !== "generic" && !payloadInjected) {
|
|
53936
|
+
const languagePayloads = this.languageGenerator.getPayloadsForLanguage(detectedLanguage);
|
|
53937
|
+
if (languagePayloads.length > 0) {
|
|
53938
|
+
const payloadLower = payload.payload.toLowerCase();
|
|
53939
|
+
const isCommandTest = payloadLower.includes("whoami") || payloadLower.includes("passwd") || payloadLower.includes("id");
|
|
53940
|
+
let selectedPayload = languagePayloads[0];
|
|
53941
|
+
if (isCommandTest) {
|
|
53942
|
+
const cmdPayload = languagePayloads.find(
|
|
53943
|
+
(lp) => lp.payload.includes("whoami") || lp.payload.includes("subprocess") || lp.payload.includes("execSync")
|
|
53944
|
+
);
|
|
53945
|
+
if (cmdPayload) selectedPayload = cmdPayload;
|
|
53946
|
+
}
|
|
53947
|
+
params[key] = selectedPayload.payload;
|
|
53948
|
+
payloadInjected = true;
|
|
53949
|
+
break;
|
|
53950
|
+
}
|
|
53951
|
+
}
|
|
53952
|
+
}
|
|
53953
|
+
if (!payloadInjected && targetParamTypes.length > 0) {
|
|
53462
53954
|
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
53463
53955
|
const propSchema = prop;
|
|
53464
53956
|
const paramNameLower = key.toLowerCase();
|
|
@@ -53468,7 +53960,8 @@ class SecurityAssessor extends BaseAssessor {
|
|
|
53468
53960
|
break;
|
|
53469
53961
|
}
|
|
53470
53962
|
}
|
|
53471
|
-
}
|
|
53963
|
+
}
|
|
53964
|
+
if (!payloadInjected) {
|
|
53472
53965
|
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
53473
53966
|
const propSchema = prop;
|
|
53474
53967
|
if (propSchema.type === "string" && !payloadInjected) {
|
|
@@ -53600,14 +54093,15 @@ class MCPAssessmentService {
|
|
|
53600
54093
|
packageLock: void 0,
|
|
53601
54094
|
privacyPolicy: void 0
|
|
53602
54095
|
};
|
|
54096
|
+
const categories = this.config.assessmentCategories;
|
|
53603
54097
|
const functionalityAssessor = new FunctionalityAssessor(this.config);
|
|
53604
|
-
const functionality = await functionalityAssessor.assess(context);
|
|
54098
|
+
const functionality = categories?.functionality !== false ? await functionalityAssessor.assess(context) : this.createEmptyFunctionalityResult();
|
|
53605
54099
|
const securityAssessor = new SecurityAssessor(this.config);
|
|
53606
|
-
const security = await securityAssessor.assess(context);
|
|
53607
|
-
const documentation = this.assessDocumentation(readmeContent || "", tools);
|
|
54100
|
+
const security = categories?.security !== false ? await securityAssessor.assess(context) : this.createEmptySecurityResult();
|
|
54101
|
+
const documentation = categories?.documentation !== false ? this.assessDocumentation(readmeContent || "", tools) : this.createEmptyDocumentationResult();
|
|
53608
54102
|
const errorHandlingAssessor = new ErrorHandlingAssessor(this.config);
|
|
53609
|
-
const errorHandling = await errorHandlingAssessor.assess(context);
|
|
53610
|
-
const usability = this.assessUsability(tools);
|
|
54103
|
+
const errorHandling = categories?.errorHandling !== false ? await errorHandlingAssessor.assess(context) : this.createEmptyErrorHandlingResult();
|
|
54104
|
+
const usability = categories?.usability !== false ? this.assessUsability(tools) : this.createEmptyUsabilityResult();
|
|
53611
54105
|
let mcpSpecCompliance;
|
|
53612
54106
|
let mcpAssessor;
|
|
53613
54107
|
if (this.config.enableExtendedAssessment) {
|
|
@@ -54227,6 +54721,71 @@ class MCPAssessmentService {
|
|
|
54227
54721
|
}
|
|
54228
54722
|
return recommendations;
|
|
54229
54723
|
}
|
|
54724
|
+
// Helper methods for creating empty results when assessments are disabled
|
|
54725
|
+
createEmptyFunctionalityResult() {
|
|
54726
|
+
return {
|
|
54727
|
+
totalTools: 0,
|
|
54728
|
+
testedTools: 0,
|
|
54729
|
+
workingTools: 0,
|
|
54730
|
+
brokenTools: [],
|
|
54731
|
+
coveragePercentage: 100,
|
|
54732
|
+
status: "PASS",
|
|
54733
|
+
explanation: "Functionality assessment skipped",
|
|
54734
|
+
toolResults: []
|
|
54735
|
+
};
|
|
54736
|
+
}
|
|
54737
|
+
createEmptySecurityResult() {
|
|
54738
|
+
return {
|
|
54739
|
+
promptInjectionTests: [],
|
|
54740
|
+
vulnerabilities: [],
|
|
54741
|
+
overallRiskLevel: "LOW",
|
|
54742
|
+
status: "PASS",
|
|
54743
|
+
explanation: "Security assessment skipped"
|
|
54744
|
+
};
|
|
54745
|
+
}
|
|
54746
|
+
createEmptyDocumentationResult() {
|
|
54747
|
+
return {
|
|
54748
|
+
status: "PASS",
|
|
54749
|
+
recommendations: [],
|
|
54750
|
+
metrics: {
|
|
54751
|
+
hasReadme: false,
|
|
54752
|
+
exampleCount: 0,
|
|
54753
|
+
requiredExamples: 3,
|
|
54754
|
+
missingExamples: [],
|
|
54755
|
+
hasInstallInstructions: false,
|
|
54756
|
+
hasUsageGuide: false,
|
|
54757
|
+
hasAPIReference: false
|
|
54758
|
+
},
|
|
54759
|
+
explanation: "Documentation assessment skipped"
|
|
54760
|
+
};
|
|
54761
|
+
}
|
|
54762
|
+
createEmptyErrorHandlingResult() {
|
|
54763
|
+
return {
|
|
54764
|
+
status: "PASS",
|
|
54765
|
+
recommendations: [],
|
|
54766
|
+
metrics: {
|
|
54767
|
+
mcpComplianceScore: 100,
|
|
54768
|
+
errorResponseQuality: "excellent",
|
|
54769
|
+
hasProperErrorCodes: true,
|
|
54770
|
+
hasDescriptiveMessages: true,
|
|
54771
|
+
validatesInputs: true
|
|
54772
|
+
},
|
|
54773
|
+
explanation: "Error handling assessment skipped"
|
|
54774
|
+
};
|
|
54775
|
+
}
|
|
54776
|
+
createEmptyUsabilityResult() {
|
|
54777
|
+
return {
|
|
54778
|
+
status: "PASS",
|
|
54779
|
+
recommendations: [],
|
|
54780
|
+
metrics: {
|
|
54781
|
+
toolNamingConvention: "consistent",
|
|
54782
|
+
parameterClarity: "clear",
|
|
54783
|
+
hasHelpfulDescriptions: true,
|
|
54784
|
+
followsBestPractices: true
|
|
54785
|
+
},
|
|
54786
|
+
explanation: "Usability assessment skipped"
|
|
54787
|
+
};
|
|
54788
|
+
}
|
|
54230
54789
|
}
|
|
54231
54790
|
const badgeVariants = cva(
|
|
54232
54791
|
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
@@ -58502,13 +59061,13 @@ const App = () => {
|
|
|
58502
59061
|
) });
|
|
58503
59062
|
if (window.location.pathname === "/oauth/callback") {
|
|
58504
59063
|
const OAuthCallback = React.lazy(
|
|
58505
|
-
() => __vitePreload(() => import("./OAuthCallback-
|
|
59064
|
+
() => __vitePreload(() => import("./OAuthCallback-D_dKq_wM.js"), true ? [] : void 0)
|
|
58506
59065
|
);
|
|
58507
59066
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthCallback, { onConnect: onOAuthConnect }) });
|
|
58508
59067
|
}
|
|
58509
59068
|
if (window.location.pathname === "/oauth/callback/debug") {
|
|
58510
59069
|
const OAuthDebugCallback = React.lazy(
|
|
58511
|
-
() => __vitePreload(() => import("./OAuthDebugCallback-
|
|
59070
|
+
() => __vitePreload(() => import("./OAuthDebugCallback-UqARwe_4.js"), true ? [] : void 0)
|
|
58512
59071
|
);
|
|
58513
59072
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthDebugCallback, { onConnect: onOAuthDebugConnect }) });
|
|
58514
59073
|
}
|
package/dist/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/mcp.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>MCP Inspector</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-B5_VY0TC.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-32-uLPhe.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root" class="w-full"></div>
|