@elliotllliu/agent-shield 0.3.1
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/LICENSE +21 -0
- package/README.md +297 -0
- package/README.zh-CN.md +130 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +265 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +24 -0
- package/dist/config.js +91 -0
- package/dist/config.js.map +1 -0
- package/dist/discover.d.ts +9 -0
- package/dist/discover.js +143 -0
- package/dist/discover.js.map +1 -0
- package/dist/llm/anthropic.d.ts +10 -0
- package/dist/llm/anthropic.js +67 -0
- package/dist/llm/anthropic.js.map +1 -0
- package/dist/llm/index.d.ts +10 -0
- package/dist/llm/index.js +41 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/ollama.d.ts +9 -0
- package/dist/llm/ollama.js +61 -0
- package/dist/llm/ollama.js.map +1 -0
- package/dist/llm/openai.d.ts +10 -0
- package/dist/llm/openai.js +66 -0
- package/dist/llm/openai.js.map +1 -0
- package/dist/llm/prompt.d.ts +3 -0
- package/dist/llm/prompt.js +31 -0
- package/dist/llm/prompt.js.map +1 -0
- package/dist/llm/types.d.ts +23 -0
- package/dist/llm/types.js +3 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/llm-analyzer.d.ts +13 -0
- package/dist/llm-analyzer.js +169 -0
- package/dist/llm-analyzer.js.map +1 -0
- package/dist/reporter/badge.d.ts +7 -0
- package/dist/reporter/badge.js +50 -0
- package/dist/reporter/badge.js.map +1 -0
- package/dist/reporter/json.d.ts +3 -0
- package/dist/reporter/json.js +5 -0
- package/dist/reporter/json.js.map +1 -0
- package/dist/reporter/terminal.d.ts +2 -0
- package/dist/reporter/terminal.js +64 -0
- package/dist/reporter/terminal.js.map +1 -0
- package/dist/rules/backdoor.d.ts +2 -0
- package/dist/rules/backdoor.js +57 -0
- package/dist/rules/backdoor.js.map +1 -0
- package/dist/rules/credential-hardcode.d.ts +2 -0
- package/dist/rules/credential-hardcode.js +57 -0
- package/dist/rules/credential-hardcode.js.map +1 -0
- package/dist/rules/crypto-mining.d.ts +2 -0
- package/dist/rules/crypto-mining.js +41 -0
- package/dist/rules/crypto-mining.js.map +1 -0
- package/dist/rules/data-exfil.d.ts +2 -0
- package/dist/rules/data-exfil.js +61 -0
- package/dist/rules/data-exfil.js.map +1 -0
- package/dist/rules/env-leak.d.ts +2 -0
- package/dist/rules/env-leak.js +43 -0
- package/dist/rules/env-leak.js.map +1 -0
- package/dist/rules/excessive-perms.d.ts +2 -0
- package/dist/rules/excessive-perms.js +50 -0
- package/dist/rules/excessive-perms.js.map +1 -0
- package/dist/rules/hidden-files.d.ts +2 -0
- package/dist/rules/hidden-files.js +52 -0
- package/dist/rules/hidden-files.js.map +1 -0
- package/dist/rules/index.d.ts +5 -0
- package/dist/rules/index.js +53 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/mcp-manifest.d.ts +2 -0
- package/dist/rules/mcp-manifest.js +270 -0
- package/dist/rules/mcp-manifest.js.map +1 -0
- package/dist/rules/network-ssrf.d.ts +2 -0
- package/dist/rules/network-ssrf.js +51 -0
- package/dist/rules/network-ssrf.js.map +1 -0
- package/dist/rules/obfuscation.d.ts +2 -0
- package/dist/rules/obfuscation.js +51 -0
- package/dist/rules/obfuscation.js.map +1 -0
- package/dist/rules/phone-home.d.ts +2 -0
- package/dist/rules/phone-home.js +38 -0
- package/dist/rules/phone-home.js.map +1 -0
- package/dist/rules/privilege.d.ts +2 -0
- package/dist/rules/privilege.js +111 -0
- package/dist/rules/privilege.js.map +1 -0
- package/dist/rules/prompt-injection.d.ts +2 -0
- package/dist/rules/prompt-injection.js +323 -0
- package/dist/rules/prompt-injection.js.map +1 -0
- package/dist/rules/reverse-shell.d.ts +2 -0
- package/dist/rules/reverse-shell.js +53 -0
- package/dist/rules/reverse-shell.js.map +1 -0
- package/dist/rules/sensitive-read.d.ts +2 -0
- package/dist/rules/sensitive-read.js +53 -0
- package/dist/rules/sensitive-read.js.map +1 -0
- package/dist/rules/skill-risks.d.ts +2 -0
- package/dist/rules/skill-risks.js +148 -0
- package/dist/rules/skill-risks.js.map +1 -0
- package/dist/rules/supply-chain.d.ts +6 -0
- package/dist/rules/supply-chain.js +105 -0
- package/dist/rules/supply-chain.js.map +1 -0
- package/dist/rules/tool-shadowing.d.ts +2 -0
- package/dist/rules/tool-shadowing.js +129 -0
- package/dist/rules/tool-shadowing.js.map +1 -0
- package/dist/rules/toxic-flow.d.ts +2 -0
- package/dist/rules/toxic-flow.js +160 -0
- package/dist/rules/toxic-flow.js.map +1 -0
- package/dist/rules/typosquatting.d.ts +2 -0
- package/dist/rules/typosquatting.js +56 -0
- package/dist/rules/typosquatting.js.map +1 -0
- package/dist/scanner/files.d.ts +5 -0
- package/dist/scanner/files.js +105 -0
- package/dist/scanner/files.js.map +1 -0
- package/dist/scanner/index.d.ts +6 -0
- package/dist/scanner/index.js +198 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/score.d.ts +14 -0
- package/dist/score.js +35 -0
- package/dist/score.js.map +1 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/yaml-simple.d.ts +6 -0
- package/dist/yaml-simple.js +98 -0
- package/dist/yaml-simple.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: skill-risks
|
|
3
|
+
* Detects high-risk patterns in agent skills that may indicate
|
|
4
|
+
* dangerous capabilities or insecure practices.
|
|
5
|
+
*
|
|
6
|
+
* Based on Snyk Agent Scan issue codes:
|
|
7
|
+
* - W007: Insecure credential handling
|
|
8
|
+
* - W009: Direct financial execution
|
|
9
|
+
* - W011: Exposure to untrusted third-party content
|
|
10
|
+
* - W012: Unverifiable external dependency (runtime fetch of instructions)
|
|
11
|
+
* - W013: System service modification
|
|
12
|
+
*/
|
|
13
|
+
// W007: Insecure credential handling — skill asks agent to output secrets verbatim
|
|
14
|
+
const INSECURE_CRED_PATTERNS = [
|
|
15
|
+
{ pattern: /(?:paste|type|enter|input|write|include|put)\s+(?:your\s+)?(?:api\s+key|token|password|secret|credential|access\s+key)\s+(?:here|below|in\s+the|into|directly)/i, description: "Asks user to paste credentials directly" },
|
|
16
|
+
{ pattern: /(?:hardcode|embed|include|put)\s+(?:the\s+)?(?:api\s+key|token|password|secret)\s+(?:in|into|inside)\s+(?:the\s+)?(?:code|file|config|script)/i, description: "Instructs embedding secrets in code" },
|
|
17
|
+
{ pattern: /(?:api_key|token|password|secret)\s*[:=]\s*["'][A-Za-z0-9_\-]{20,}["']/i, description: "Appears to contain a hardcoded credential in instructions" },
|
|
18
|
+
];
|
|
19
|
+
// W009: Financial execution capabilities
|
|
20
|
+
const FINANCIAL_PATTERNS = [
|
|
21
|
+
{ pattern: /(?:send|transfer|move|wire)\s+(?:money|funds|payment|bitcoin|crypto|eth|btc|usdt)/i, description: "Direct money transfer capability" },
|
|
22
|
+
{ pattern: /(?:execute|place|submit)\s+(?:a\s+)?(?:trade|order|transaction|purchase|buy\s+order|sell\s+order)/i, description: "Financial trade/order execution" },
|
|
23
|
+
{ pattern: /(?:stripe|paypal|braintree|square)\.(?:charges?|payments?)\.create/i, description: "Payment processing API call" },
|
|
24
|
+
{ pattern: /(?:web3|ethers|solana).*(?:sendTransaction|transfer|sign)/i, description: "Blockchain transaction execution" },
|
|
25
|
+
];
|
|
26
|
+
// W011: Untrusted content exposure
|
|
27
|
+
const UNTRUSTED_CONTENT_PATTERNS = [
|
|
28
|
+
{ pattern: /(?:browse|visit|open|navigate|fetch|scrape|crawl)\s+(?:any\s+)?(?:arbitrary|user[- ]?provided|unknown|untrusted)\s+(?:url|website|webpage|link|page)/i, description: "Browses arbitrary user-provided URLs" },
|
|
29
|
+
{ pattern: /(?:read|parse|analyze|process)\s+(?:social\s+media|forum|reddit|twitter|comments?|reviews?|posts?)\s+(?:from|on|at)/i, description: "Processes untrusted social media content" },
|
|
30
|
+
{ pattern: /(?:download|fetch|get|retrieve)\s+(?:content|data|text|html)\s+from\s+(?:any|arbitrary|user)/i, description: "Downloads content from arbitrary sources" },
|
|
31
|
+
];
|
|
32
|
+
// W012: Unverifiable external dependency — runtime code/instruction fetch
|
|
33
|
+
const EXTERNAL_DEP_PATTERNS = [
|
|
34
|
+
{ pattern: /(?:fetch|download|pull|get)\s+(?:the\s+)?(?:latest|updated?|current)\s+(?:instructions?|prompts?|config|rules?|script)\s+from\s+/i, description: "Fetches instructions from external URL at runtime" },
|
|
35
|
+
{ pattern: /(?:auto[- ]?update|self[- ]?update|live[- ]?reload)\s+(?:from|via|using)\s+/i, description: "Auto-update mechanism from external source" },
|
|
36
|
+
{ pattern: /(?:eval|exec|execute|run)\s*\(\s*(?:await\s+)?(?:fetch|axios|got|request)\s*\(/i, description: "Fetches and executes remote code" },
|
|
37
|
+
{ pattern: /(?:import|require|load)\s*\(\s*(?:['"`]https?:\/\/|url|endpoint)/i, description: "Dynamic import from remote URL" },
|
|
38
|
+
];
|
|
39
|
+
// W013: System service modification
|
|
40
|
+
const SYSTEM_MOD_PATTERNS = [
|
|
41
|
+
{ pattern: /(?:sudo|doas|runas)\s+/i, description: "Elevated privilege execution" },
|
|
42
|
+
{ pattern: /(?:systemctl|service|launchctl|sc\.exe)\s+(?:start|stop|enable|disable|restart|create)/i, description: "System service management" },
|
|
43
|
+
{ pattern: /(?:crontab|schtasks|at\s+\d|launchd)\s+/i, description: "Scheduled task creation" },
|
|
44
|
+
{ pattern: /(?:chmod\s+[0-7]*[1-7][0-7]*|chown\s+root|setuid|setgid)/i, description: "Permission/ownership modification" },
|
|
45
|
+
{ pattern: /(?:\/etc\/(?:passwd|shadow|sudoers|crontab|hosts|resolv|fstab|profile|rc\.local))/i, description: "Modifies critical system configuration files" },
|
|
46
|
+
{ pattern: /(?:iptables|ufw|firewalld|netsh\s+firewall)\s+/i, description: "Firewall rule modification" },
|
|
47
|
+
{ pattern: /(?:~\/\.bashrc|~\/\.zshrc|~\/\.profile|~\/\.bash_profile|\/etc\/environment)\b/i, description: "Shell profile/environment modification" },
|
|
48
|
+
];
|
|
49
|
+
export const skillRisks = {
|
|
50
|
+
id: "skill-risks",
|
|
51
|
+
name: "Skill Risk Assessment",
|
|
52
|
+
description: "Detects high-risk capabilities in skills: financial ops, untrusted content, external deps, system modification",
|
|
53
|
+
run(files) {
|
|
54
|
+
const findings = [];
|
|
55
|
+
for (const file of files) {
|
|
56
|
+
const isSkillMd = file.relativePath.toLowerCase().includes("skill.md");
|
|
57
|
+
const isMarkdown = file.ext === ".md";
|
|
58
|
+
const isCode = [".ts", ".js", ".py", ".sh", ".bash"].includes(file.ext);
|
|
59
|
+
const isConfig = [".json", ".yaml", ".yml"].includes(file.ext);
|
|
60
|
+
if (!isMarkdown && !isCode && !isConfig)
|
|
61
|
+
continue;
|
|
62
|
+
for (let i = 0; i < file.lines.length; i++) {
|
|
63
|
+
const line = file.lines[i];
|
|
64
|
+
const trimmed = line.trimStart();
|
|
65
|
+
if (trimmed.startsWith("//") || trimmed.startsWith("#") && !trimmed.startsWith("#!"))
|
|
66
|
+
continue;
|
|
67
|
+
// W007: Insecure credential handling (in markdown/docs)
|
|
68
|
+
if (isMarkdown) {
|
|
69
|
+
for (const { pattern, description } of INSECURE_CRED_PATTERNS) {
|
|
70
|
+
if (pattern.test(line)) {
|
|
71
|
+
findings.push({
|
|
72
|
+
rule: "skill-risks",
|
|
73
|
+
severity: "warning",
|
|
74
|
+
file: file.relativePath,
|
|
75
|
+
line: i + 1,
|
|
76
|
+
message: `Insecure credential handling: ${description}`,
|
|
77
|
+
evidence: line.trim().substring(0, 120),
|
|
78
|
+
});
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// W009: Financial execution
|
|
84
|
+
for (const { pattern, description } of FINANCIAL_PATTERNS) {
|
|
85
|
+
if (pattern.test(line)) {
|
|
86
|
+
findings.push({
|
|
87
|
+
rule: "skill-risks",
|
|
88
|
+
severity: "warning",
|
|
89
|
+
file: file.relativePath,
|
|
90
|
+
line: i + 1,
|
|
91
|
+
message: `Financial execution: ${description}`,
|
|
92
|
+
evidence: line.trim().substring(0, 120),
|
|
93
|
+
});
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// W011: Untrusted content (primarily in SKILL.md)
|
|
98
|
+
if (isSkillMd || isMarkdown) {
|
|
99
|
+
for (const { pattern, description } of UNTRUSTED_CONTENT_PATTERNS) {
|
|
100
|
+
if (pattern.test(line)) {
|
|
101
|
+
findings.push({
|
|
102
|
+
rule: "skill-risks",
|
|
103
|
+
severity: "warning",
|
|
104
|
+
file: file.relativePath,
|
|
105
|
+
line: i + 1,
|
|
106
|
+
message: `Untrusted content exposure: ${description}`,
|
|
107
|
+
evidence: line.trim().substring(0, 120),
|
|
108
|
+
});
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// W012: External dependency
|
|
114
|
+
if (isCode || isMarkdown) {
|
|
115
|
+
for (const { pattern, description } of EXTERNAL_DEP_PATTERNS) {
|
|
116
|
+
if (pattern.test(line)) {
|
|
117
|
+
findings.push({
|
|
118
|
+
rule: "skill-risks",
|
|
119
|
+
severity: isCode ? "critical" : "warning",
|
|
120
|
+
file: file.relativePath,
|
|
121
|
+
line: i + 1,
|
|
122
|
+
message: `Unverifiable external dependency: ${description}`,
|
|
123
|
+
evidence: line.trim().substring(0, 120),
|
|
124
|
+
});
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// W013: System modification
|
|
130
|
+
for (const { pattern, description } of SYSTEM_MOD_PATTERNS) {
|
|
131
|
+
if (pattern.test(line)) {
|
|
132
|
+
findings.push({
|
|
133
|
+
rule: "skill-risks",
|
|
134
|
+
severity: isSkillMd ? "warning" : "info",
|
|
135
|
+
file: file.relativePath,
|
|
136
|
+
line: i + 1,
|
|
137
|
+
message: `System modification: ${description}`,
|
|
138
|
+
evidence: line.trim().substring(0, 120),
|
|
139
|
+
});
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return findings;
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
//# sourceMappingURL=skill-risks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-risks.js","sourceRoot":"","sources":["../../src/rules/skill-risks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
/**
|
|
5
|
+
* Rule: supply-chain
|
|
6
|
+
* Runs npm audit to detect known CVEs in dependencies.
|
|
7
|
+
*/
|
|
8
|
+
export const supplyChainRule = {
|
|
9
|
+
id: "supply-chain",
|
|
10
|
+
name: "Supply Chain Audit",
|
|
11
|
+
description: "Checks for known CVEs in npm/pip dependencies",
|
|
12
|
+
run(files) {
|
|
13
|
+
const findings = [];
|
|
14
|
+
// Determine the target directory from the first file
|
|
15
|
+
if (files.length === 0)
|
|
16
|
+
return findings;
|
|
17
|
+
const targetDir = files[0].path.replace(files[0].relativePath, "").replace(/\/$/, "");
|
|
18
|
+
// Check for package.json
|
|
19
|
+
const pkgJsonPath = join(targetDir, "package.json");
|
|
20
|
+
const hasNodeModules = existsSync(join(targetDir, "node_modules"));
|
|
21
|
+
const hasPkgJson = existsSync(pkgJsonPath);
|
|
22
|
+
const hasLockFile = existsSync(join(targetDir, "package-lock.json")) ||
|
|
23
|
+
existsSync(join(targetDir, "yarn.lock")) ||
|
|
24
|
+
existsSync(join(targetDir, "pnpm-lock.yaml"));
|
|
25
|
+
if (hasPkgJson && (hasNodeModules || hasLockFile)) {
|
|
26
|
+
try {
|
|
27
|
+
// npm audit returns exit code > 0 when vulnerabilities are found
|
|
28
|
+
const result = execSync("npm audit --json 2>/dev/null", {
|
|
29
|
+
cwd: targetDir,
|
|
30
|
+
encoding: "utf-8",
|
|
31
|
+
timeout: 30000,
|
|
32
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
33
|
+
});
|
|
34
|
+
parseNpmAudit(result, findings);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
// npm audit exits non-zero when vulns are found
|
|
38
|
+
if (err && typeof err === "object" && "stdout" in err) {
|
|
39
|
+
parseNpmAudit(err.stdout, findings);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else if (hasPkgJson) {
|
|
44
|
+
// Has package.json but no lock file — check deps manually
|
|
45
|
+
try {
|
|
46
|
+
const pkgContent = files.find((f) => f.relativePath === "package.json");
|
|
47
|
+
if (pkgContent) {
|
|
48
|
+
const pkg = JSON.parse(pkgContent.content);
|
|
49
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
50
|
+
const depCount = Object.keys(deps).length;
|
|
51
|
+
if (depCount > 0) {
|
|
52
|
+
findings.push({
|
|
53
|
+
rule: "supply-chain",
|
|
54
|
+
severity: "info",
|
|
55
|
+
file: "package.json",
|
|
56
|
+
message: `${depCount} dependencies declared — run 'npm install && npm audit' for full CVE check`,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// ignore parse errors
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Check for requirements.txt (Python)
|
|
66
|
+
const reqTxt = files.find((f) => f.relativePath === "requirements.txt" || f.relativePath.endsWith("/requirements.txt"));
|
|
67
|
+
if (reqTxt) {
|
|
68
|
+
findings.push({
|
|
69
|
+
rule: "supply-chain",
|
|
70
|
+
severity: "info",
|
|
71
|
+
file: reqTxt.relativePath,
|
|
72
|
+
message: "Python requirements.txt found — run 'pip-audit' for CVE check",
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return findings;
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
function parseNpmAudit(output, findings) {
|
|
79
|
+
try {
|
|
80
|
+
const audit = JSON.parse(output);
|
|
81
|
+
if (audit.vulnerabilities) {
|
|
82
|
+
for (const [name, vuln] of Object.entries(audit.vulnerabilities)) {
|
|
83
|
+
const severity = vuln.severity || "moderate";
|
|
84
|
+
const via = Array.isArray(vuln.via) ? vuln.via : [];
|
|
85
|
+
const cves = via
|
|
86
|
+
.filter((v) => typeof v === "object" && v !== null && "url" in v)
|
|
87
|
+
.map((v) => String(v.url))
|
|
88
|
+
.join(", ");
|
|
89
|
+
const mappedSeverity = severity === "critical" || severity === "high" ? "critical" :
|
|
90
|
+
severity === "moderate" ? "warning" : "info";
|
|
91
|
+
findings.push({
|
|
92
|
+
rule: "supply-chain",
|
|
93
|
+
severity: mappedSeverity,
|
|
94
|
+
file: "package.json",
|
|
95
|
+
message: `${name} — ${severity} severity${cves ? ` (${cves})` : ""}`,
|
|
96
|
+
evidence: typeof vuln.range === "string" ? `affected: ${vuln.range}` : undefined,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// unparseable output
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=supply-chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supply-chain.js","sourceRoot":"","sources":["../../src/rules/supply-chain.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: tool-shadowing
|
|
3
|
+
* Detects when a tool description references tools from other MCP servers,
|
|
4
|
+
* potentially hijacking or overriding their behavior.
|
|
5
|
+
* Also detects cross-server tool name conflicts from MCP config files.
|
|
6
|
+
*/
|
|
7
|
+
// Common MCP tool names that could be shadowed
|
|
8
|
+
const WELL_KNOWN_TOOLS = [
|
|
9
|
+
"read_file", "write_file", "list_files", "search_files",
|
|
10
|
+
"execute_command", "run_terminal_command",
|
|
11
|
+
"browser_action", "web_search",
|
|
12
|
+
"create_file", "edit_file", "delete_file",
|
|
13
|
+
"git_commit", "git_push", "git_pull",
|
|
14
|
+
"send_message", "read_email",
|
|
15
|
+
];
|
|
16
|
+
// Patterns indicating cross-tool reference in descriptions
|
|
17
|
+
const CROSS_TOOL_PATTERNS = [
|
|
18
|
+
{ pattern: /(?:instead\s+of|replace|override|intercept|wrap)\s+(?:the\s+)?(?:original|default|built-in|other)\s+(?:tool|function|command)/i, description: "Claims to replace another tool" },
|
|
19
|
+
{ pattern: /(?:call|use|invoke)\s+(?:this\s+tool\s+)?(?:instead\s+of|before|after)\s+["']?\w+["']?/i, description: "Redirects from another tool to this one" },
|
|
20
|
+
{ pattern: /(?:this|my)\s+(?:version|implementation)\s+of\s+["']?\w+["']?\s+(?:is|should\s+be)/i, description: "Claims to be a version of another tool" },
|
|
21
|
+
{ pattern: /(?:enhanced|improved|better|secure)\s+(?:version|replacement)\s+(?:of|for)\s+/i, description: "Claims to be an enhanced version" },
|
|
22
|
+
{ pattern: /(?:whenever|every\s+time)\s+(?:you|the\s+agent)\s+(?:would\s+)?(?:use|call|invoke)\s+["']?\w+["']?,?\s+(?:use|call)\s+(?:this|me)/i, description: "Hijacks calls to another tool" },
|
|
23
|
+
];
|
|
24
|
+
export const toolShadowing = {
|
|
25
|
+
id: "tool-shadowing",
|
|
26
|
+
name: "Tool Shadowing Detection",
|
|
27
|
+
description: "Detects tools that attempt to shadow, override, or hijack other tools",
|
|
28
|
+
run(files) {
|
|
29
|
+
const findings = [];
|
|
30
|
+
// Collect tool names from MCP config files
|
|
31
|
+
const toolsByServer = new Map();
|
|
32
|
+
for (const file of files) {
|
|
33
|
+
// Check JSON config files for MCP tool definitions
|
|
34
|
+
if (file.ext === ".json") {
|
|
35
|
+
try {
|
|
36
|
+
const config = JSON.parse(file.content);
|
|
37
|
+
extractMcpTools(config, file.relativePath, toolsByServer);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Not valid JSON, skip
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Check tool descriptions for cross-tool reference patterns
|
|
44
|
+
if ([".json", ".md", ".yaml", ".yml", ".ts", ".js"].includes(file.ext)) {
|
|
45
|
+
for (let i = 0; i < file.lines.length; i++) {
|
|
46
|
+
const line = file.lines[i];
|
|
47
|
+
for (const { pattern, description } of CROSS_TOOL_PATTERNS) {
|
|
48
|
+
pattern.lastIndex = 0;
|
|
49
|
+
if (pattern.test(line)) {
|
|
50
|
+
findings.push({
|
|
51
|
+
rule: "tool-shadowing",
|
|
52
|
+
severity: "critical",
|
|
53
|
+
file: file.relativePath,
|
|
54
|
+
line: i + 1,
|
|
55
|
+
message: `Tool shadowing: ${description}`,
|
|
56
|
+
evidence: line.trim().substring(0, 120),
|
|
57
|
+
});
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Check if description references well-known tool names
|
|
62
|
+
const lineLower = line.toLowerCase();
|
|
63
|
+
for (const toolName of WELL_KNOWN_TOOLS) {
|
|
64
|
+
if (lineLower.includes(toolName) &&
|
|
65
|
+
/(?:instead|replace|override|intercept|before|after|wrap)/i.test(line)) {
|
|
66
|
+
findings.push({
|
|
67
|
+
rule: "tool-shadowing",
|
|
68
|
+
severity: "critical",
|
|
69
|
+
file: file.relativePath,
|
|
70
|
+
line: i + 1,
|
|
71
|
+
message: `References well-known tool "${toolName}" with override intent`,
|
|
72
|
+
evidence: line.trim().substring(0, 120),
|
|
73
|
+
});
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Check for duplicate tool names across servers
|
|
81
|
+
const allToolNames = new Map(); // toolName -> [server1, server2]
|
|
82
|
+
for (const [serverName, { tools }] of toolsByServer) {
|
|
83
|
+
for (const tool of tools) {
|
|
84
|
+
if (!allToolNames.has(tool))
|
|
85
|
+
allToolNames.set(tool, []);
|
|
86
|
+
allToolNames.get(tool).push(serverName);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
for (const [toolName, servers] of allToolNames) {
|
|
90
|
+
if (servers.length > 1) {
|
|
91
|
+
findings.push({
|
|
92
|
+
rule: "tool-shadowing",
|
|
93
|
+
severity: "critical",
|
|
94
|
+
file: servers[0],
|
|
95
|
+
message: `Tool name conflict: "${toolName}" defined in ${servers.length} servers (${servers.join(", ")}) — potential tool shadowing attack`,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return findings;
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
function extractMcpTools(obj, filePath, result, serverName) {
|
|
103
|
+
if (!obj || typeof obj !== "object")
|
|
104
|
+
return;
|
|
105
|
+
const record = obj;
|
|
106
|
+
// Look for MCP server definitions with tools
|
|
107
|
+
if (record.tools && Array.isArray(record.tools)) {
|
|
108
|
+
const tools = record.tools
|
|
109
|
+
.map((t) => String(t.name || t.id || ""))
|
|
110
|
+
.filter(Boolean);
|
|
111
|
+
if (tools.length > 0) {
|
|
112
|
+
const name = serverName || filePath;
|
|
113
|
+
result.set(name, { tools, file: filePath });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Recurse into mcpServers config
|
|
117
|
+
if (record.mcpServers && typeof record.mcpServers === "object") {
|
|
118
|
+
for (const [name, config] of Object.entries(record.mcpServers)) {
|
|
119
|
+
extractMcpTools(config, filePath, result, name);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Recurse into servers
|
|
123
|
+
if (record.servers && typeof record.servers === "object") {
|
|
124
|
+
for (const [name, config] of Object.entries(record.servers)) {
|
|
125
|
+
extractMcpTools(config, filePath, result, name);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=tool-shadowing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-shadowing.js","sourceRoot":"","sources":["../../src/rules/tool-shadowing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// Patterns for classifying tool capabilities
|
|
2
|
+
const UNTRUSTED_INDICATORS = [
|
|
3
|
+
/(?:fetch|browse|scrape|crawl|read)[_\s]*(?:url|web|page|site|link)/i,
|
|
4
|
+
/(?:user[- ]?(?:provided|input|supplied)|external|third[- ]?party)/i,
|
|
5
|
+
/(?:search|query)\s+(?:the\s+)?(?:web|internet|google|bing)/i,
|
|
6
|
+
/(?:download|get)\s+(?:from|content)/i,
|
|
7
|
+
/(?:parse|read)\s+(?:email|message|comment|post|tweet|rss)/i,
|
|
8
|
+
/browse\s+(?:any|arbitrary)\s+(?:web|url|page|site)/i,
|
|
9
|
+
];
|
|
10
|
+
const PRIVATE_DATA_INDICATORS = [
|
|
11
|
+
/(?:read|access|get|list)\s*(?:file|directory|folder|document)/i,
|
|
12
|
+
/(?:database|db|sql|query|select)\s/i,
|
|
13
|
+
/(?:user\s+data|personal|private|confidential|sensitive)/i,
|
|
14
|
+
/(?:credential|password|secret|token|key)\s/i,
|
|
15
|
+
/(?:history|log|conversation|chat|message)/i,
|
|
16
|
+
/(?:config|setting|preference|profile)/i,
|
|
17
|
+
];
|
|
18
|
+
const PUBLIC_SINK_INDICATORS = [
|
|
19
|
+
/(?:send|post|publish|share|upload|transmit|forward)\s/i,
|
|
20
|
+
/(?:email|message|notification|webhook|api\s+call)/i,
|
|
21
|
+
/(?:slack|discord|telegram|whatsapp|twitter|github)/i,
|
|
22
|
+
/(?:http|https|request|fetch)\s*\(/i,
|
|
23
|
+
/(?:write|save|export)\s+(?:to\s+)?(?:external|remote|cloud)/i,
|
|
24
|
+
];
|
|
25
|
+
const DESTRUCTIVE_INDICATORS = [
|
|
26
|
+
/(?:delete|remove|drop|truncate|destroy|purge|wipe|erase)/i,
|
|
27
|
+
/(?:overwrite|replace|modify|update|alter)\s+(?:file|data|record|config)/i,
|
|
28
|
+
/(?:execute|run|exec|spawn|shell)\s+(?:command|script|process)/i,
|
|
29
|
+
/(?:format|reset|factory\s+reset|reinstall)/i,
|
|
30
|
+
/(?:revoke|disable|block|ban|suspend)/i,
|
|
31
|
+
];
|
|
32
|
+
function classifyTool(name, description, serverName) {
|
|
33
|
+
const cap = {
|
|
34
|
+
name,
|
|
35
|
+
server: serverName,
|
|
36
|
+
untrustedContent: false,
|
|
37
|
+
privateData: false,
|
|
38
|
+
publicSink: false,
|
|
39
|
+
destructive: false,
|
|
40
|
+
reasons: [],
|
|
41
|
+
};
|
|
42
|
+
const text = `${name} ${description}`.toLowerCase();
|
|
43
|
+
for (const re of UNTRUSTED_INDICATORS) {
|
|
44
|
+
if (re.test(text)) {
|
|
45
|
+
cap.untrustedContent = true;
|
|
46
|
+
cap.reasons.push("untrusted-content");
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
for (const re of PRIVATE_DATA_INDICATORS) {
|
|
51
|
+
if (re.test(text)) {
|
|
52
|
+
cap.privateData = true;
|
|
53
|
+
cap.reasons.push("private-data");
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
for (const re of PUBLIC_SINK_INDICATORS) {
|
|
58
|
+
if (re.test(text)) {
|
|
59
|
+
cap.publicSink = true;
|
|
60
|
+
cap.reasons.push("public-sink");
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
for (const re of DESTRUCTIVE_INDICATORS) {
|
|
65
|
+
if (re.test(text)) {
|
|
66
|
+
cap.destructive = true;
|
|
67
|
+
cap.reasons.push("destructive");
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return cap;
|
|
72
|
+
}
|
|
73
|
+
/** Extract tools from MCP config JSON */
|
|
74
|
+
function extractTools(config, filePath) {
|
|
75
|
+
const tools = [];
|
|
76
|
+
const servers = (config.mcpServers || config.servers || {});
|
|
77
|
+
for (const [serverName, serverConfig] of Object.entries(servers)) {
|
|
78
|
+
if (!serverConfig || typeof serverConfig !== "object")
|
|
79
|
+
continue;
|
|
80
|
+
const sc = serverConfig;
|
|
81
|
+
// Tools array
|
|
82
|
+
if (Array.isArray(sc.tools)) {
|
|
83
|
+
for (const tool of sc.tools) {
|
|
84
|
+
const name = String(tool.name || tool.id || "unknown");
|
|
85
|
+
const desc = String(tool.description || "");
|
|
86
|
+
tools.push(classifyTool(name, desc, serverName));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// If no tools array, classify the server itself by name/description
|
|
90
|
+
if (!sc.tools) {
|
|
91
|
+
const desc = String(sc.description || sc.command || "");
|
|
92
|
+
tools.push(classifyTool(serverName, desc, serverName));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return tools;
|
|
96
|
+
}
|
|
97
|
+
export const toxicFlow = {
|
|
98
|
+
id: "toxic-flow",
|
|
99
|
+
name: "Toxic Flow Detection",
|
|
100
|
+
description: "Detects dangerous tool combinations that enable cross-tool data exfiltration or destructive attacks",
|
|
101
|
+
run(files) {
|
|
102
|
+
const findings = [];
|
|
103
|
+
const allTools = [];
|
|
104
|
+
// Collect tools from all JSON config files
|
|
105
|
+
for (const file of files) {
|
|
106
|
+
if (file.ext !== ".json")
|
|
107
|
+
continue;
|
|
108
|
+
try {
|
|
109
|
+
const config = JSON.parse(file.content);
|
|
110
|
+
const tools = extractTools(config, file.relativePath);
|
|
111
|
+
allTools.push(...tools);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Not valid JSON
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (allTools.length === 0)
|
|
118
|
+
return findings;
|
|
119
|
+
// TF001: Data Leak — untrusted content + private data + public sink
|
|
120
|
+
const hasUntrusted = allTools.filter(t => t.untrustedContent);
|
|
121
|
+
const hasPrivate = allTools.filter(t => t.privateData);
|
|
122
|
+
const hasSink = allTools.filter(t => t.publicSink);
|
|
123
|
+
if (hasUntrusted.length > 0 && hasPrivate.length > 0 && hasSink.length > 0) {
|
|
124
|
+
findings.push({
|
|
125
|
+
rule: "toxic-flow",
|
|
126
|
+
severity: "critical",
|
|
127
|
+
file: "MCP configuration",
|
|
128
|
+
message: `TF001 Data Leak: Tool combination enables data exfiltration — ` +
|
|
129
|
+
`untrusted input (${hasUntrusted.map(t => t.name).join(", ")}) → ` +
|
|
130
|
+
`private data (${hasPrivate.map(t => t.name).join(", ")}) → ` +
|
|
131
|
+
`public sink (${hasSink.map(t => t.name).join(", ")})`,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
// TF002: Destructive — untrusted content + destructive action
|
|
135
|
+
const hasDestructive = allTools.filter(t => t.destructive);
|
|
136
|
+
if (hasUntrusted.length > 0 && hasDestructive.length > 0) {
|
|
137
|
+
findings.push({
|
|
138
|
+
rule: "toxic-flow",
|
|
139
|
+
severity: "critical",
|
|
140
|
+
file: "MCP configuration",
|
|
141
|
+
message: `TF002 Destructive Flow: Untrusted content could trigger destructive actions — ` +
|
|
142
|
+
`untrusted (${hasUntrusted.map(t => t.name).join(", ")}) → ` +
|
|
143
|
+
`destructive (${hasDestructive.map(t => t.name).join(", ")})`,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
// Single tool that combines multiple risky capabilities
|
|
147
|
+
for (const tool of allTools) {
|
|
148
|
+
if (tool.untrustedContent && tool.privateData && tool.publicSink) {
|
|
149
|
+
findings.push({
|
|
150
|
+
rule: "toxic-flow",
|
|
151
|
+
severity: "critical",
|
|
152
|
+
file: "MCP configuration",
|
|
153
|
+
message: `Single tool "${tool.name}" (${tool.server}) combines untrusted content, private data access, and public sink — high exfiltration risk`,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return findings;
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
//# sourceMappingURL=toxic-flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toxic-flow.js","sourceRoot":"","sources":["../../src/rules/toxic-flow.ts"],"names":[],"mappings":"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"}
|