@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.
Files changed (121) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +297 -0
  3. package/README.zh-CN.md +130 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +265 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/config.d.ts +24 -0
  8. package/dist/config.js +91 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/discover.d.ts +9 -0
  11. package/dist/discover.js +143 -0
  12. package/dist/discover.js.map +1 -0
  13. package/dist/llm/anthropic.d.ts +10 -0
  14. package/dist/llm/anthropic.js +67 -0
  15. package/dist/llm/anthropic.js.map +1 -0
  16. package/dist/llm/index.d.ts +10 -0
  17. package/dist/llm/index.js +41 -0
  18. package/dist/llm/index.js.map +1 -0
  19. package/dist/llm/ollama.d.ts +9 -0
  20. package/dist/llm/ollama.js +61 -0
  21. package/dist/llm/ollama.js.map +1 -0
  22. package/dist/llm/openai.d.ts +10 -0
  23. package/dist/llm/openai.js +66 -0
  24. package/dist/llm/openai.js.map +1 -0
  25. package/dist/llm/prompt.d.ts +3 -0
  26. package/dist/llm/prompt.js +31 -0
  27. package/dist/llm/prompt.js.map +1 -0
  28. package/dist/llm/types.d.ts +23 -0
  29. package/dist/llm/types.js +3 -0
  30. package/dist/llm/types.js.map +1 -0
  31. package/dist/llm-analyzer.d.ts +13 -0
  32. package/dist/llm-analyzer.js +169 -0
  33. package/dist/llm-analyzer.js.map +1 -0
  34. package/dist/reporter/badge.d.ts +7 -0
  35. package/dist/reporter/badge.js +50 -0
  36. package/dist/reporter/badge.js.map +1 -0
  37. package/dist/reporter/json.d.ts +3 -0
  38. package/dist/reporter/json.js +5 -0
  39. package/dist/reporter/json.js.map +1 -0
  40. package/dist/reporter/terminal.d.ts +2 -0
  41. package/dist/reporter/terminal.js +64 -0
  42. package/dist/reporter/terminal.js.map +1 -0
  43. package/dist/rules/backdoor.d.ts +2 -0
  44. package/dist/rules/backdoor.js +57 -0
  45. package/dist/rules/backdoor.js.map +1 -0
  46. package/dist/rules/credential-hardcode.d.ts +2 -0
  47. package/dist/rules/credential-hardcode.js +57 -0
  48. package/dist/rules/credential-hardcode.js.map +1 -0
  49. package/dist/rules/crypto-mining.d.ts +2 -0
  50. package/dist/rules/crypto-mining.js +41 -0
  51. package/dist/rules/crypto-mining.js.map +1 -0
  52. package/dist/rules/data-exfil.d.ts +2 -0
  53. package/dist/rules/data-exfil.js +61 -0
  54. package/dist/rules/data-exfil.js.map +1 -0
  55. package/dist/rules/env-leak.d.ts +2 -0
  56. package/dist/rules/env-leak.js +43 -0
  57. package/dist/rules/env-leak.js.map +1 -0
  58. package/dist/rules/excessive-perms.d.ts +2 -0
  59. package/dist/rules/excessive-perms.js +50 -0
  60. package/dist/rules/excessive-perms.js.map +1 -0
  61. package/dist/rules/hidden-files.d.ts +2 -0
  62. package/dist/rules/hidden-files.js +52 -0
  63. package/dist/rules/hidden-files.js.map +1 -0
  64. package/dist/rules/index.d.ts +5 -0
  65. package/dist/rules/index.js +53 -0
  66. package/dist/rules/index.js.map +1 -0
  67. package/dist/rules/mcp-manifest.d.ts +2 -0
  68. package/dist/rules/mcp-manifest.js +270 -0
  69. package/dist/rules/mcp-manifest.js.map +1 -0
  70. package/dist/rules/network-ssrf.d.ts +2 -0
  71. package/dist/rules/network-ssrf.js +51 -0
  72. package/dist/rules/network-ssrf.js.map +1 -0
  73. package/dist/rules/obfuscation.d.ts +2 -0
  74. package/dist/rules/obfuscation.js +51 -0
  75. package/dist/rules/obfuscation.js.map +1 -0
  76. package/dist/rules/phone-home.d.ts +2 -0
  77. package/dist/rules/phone-home.js +38 -0
  78. package/dist/rules/phone-home.js.map +1 -0
  79. package/dist/rules/privilege.d.ts +2 -0
  80. package/dist/rules/privilege.js +111 -0
  81. package/dist/rules/privilege.js.map +1 -0
  82. package/dist/rules/prompt-injection.d.ts +2 -0
  83. package/dist/rules/prompt-injection.js +323 -0
  84. package/dist/rules/prompt-injection.js.map +1 -0
  85. package/dist/rules/reverse-shell.d.ts +2 -0
  86. package/dist/rules/reverse-shell.js +53 -0
  87. package/dist/rules/reverse-shell.js.map +1 -0
  88. package/dist/rules/sensitive-read.d.ts +2 -0
  89. package/dist/rules/sensitive-read.js +53 -0
  90. package/dist/rules/sensitive-read.js.map +1 -0
  91. package/dist/rules/skill-risks.d.ts +2 -0
  92. package/dist/rules/skill-risks.js +148 -0
  93. package/dist/rules/skill-risks.js.map +1 -0
  94. package/dist/rules/supply-chain.d.ts +6 -0
  95. package/dist/rules/supply-chain.js +105 -0
  96. package/dist/rules/supply-chain.js.map +1 -0
  97. package/dist/rules/tool-shadowing.d.ts +2 -0
  98. package/dist/rules/tool-shadowing.js +129 -0
  99. package/dist/rules/tool-shadowing.js.map +1 -0
  100. package/dist/rules/toxic-flow.d.ts +2 -0
  101. package/dist/rules/toxic-flow.js +160 -0
  102. package/dist/rules/toxic-flow.js.map +1 -0
  103. package/dist/rules/typosquatting.d.ts +2 -0
  104. package/dist/rules/typosquatting.js +56 -0
  105. package/dist/rules/typosquatting.js.map +1 -0
  106. package/dist/scanner/files.d.ts +5 -0
  107. package/dist/scanner/files.js +105 -0
  108. package/dist/scanner/files.js.map +1 -0
  109. package/dist/scanner/index.d.ts +6 -0
  110. package/dist/scanner/index.js +198 -0
  111. package/dist/scanner/index.js.map +1 -0
  112. package/dist/score.d.ts +14 -0
  113. package/dist/score.js +35 -0
  114. package/dist/score.js.map +1 -0
  115. package/dist/types.d.ts +60 -0
  116. package/dist/types.js +2 -0
  117. package/dist/types.js.map +1 -0
  118. package/dist/yaml-simple.d.ts +6 -0
  119. package/dist/yaml-simple.js +98 -0
  120. package/dist/yaml-simple.js.map +1 -0
  121. package/package.json +72 -0
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Rule: mcp-manifest
3
+ * Validates MCP (Model Context Protocol) server configurations.
4
+ *
5
+ * Checks:
6
+ * 1. Declared tools/resources vs actual code behavior
7
+ * 2. Overly broad tool descriptions that could mislead agents
8
+ * 3. Undeclared file system / network / exec capabilities
9
+ * 4. Suspicious tool names or descriptions
10
+ */
11
+ // Patterns indicating MCP server tool registration
12
+ const TOOL_REGISTER_RE = /\.tool\s*\(|addTool\s*\(|registerTool\s*\(|server\.setRequestHandler.*ListTools|tools:\s*\[/;
13
+ // Patterns for MCP resource registration
14
+ const RESOURCE_REGISTER_RE = /\.resource\s*\(|addResource\s*\(|registerResource\s*\(|server\.setRequestHandler.*ListResources|resources:\s*\[/;
15
+ // Dangerous patterns in tool implementations
16
+ const DANGEROUS_TOOL_PATTERNS = [
17
+ { pattern: /child_process|execSync|exec\(|spawn\(/, desc: "Tool executes shell commands", severity: "critical" },
18
+ { pattern: /fs\.unlink|fs\.rmdir|fs\.rm\b|rimraf/, desc: "Tool deletes files", severity: "warning" },
19
+ { pattern: /fs\.writeFile|fs\.appendFile|fs\.createWriteStream/, desc: "Tool writes to file system", severity: "warning" },
20
+ { pattern: /fetch\s*\(|axios|http\.request|https\.request/, desc: "Tool makes outbound HTTP requests", severity: "warning" },
21
+ { pattern: /eval\s*\(|new\s+Function\s*\(/, desc: "Tool uses dynamic code execution", severity: "critical" },
22
+ { pattern: /\.ssh|\.aws|\.env\b|credentials|secret/i, desc: "Tool accesses sensitive paths/credentials", severity: "critical" },
23
+ ];
24
+ // Suspicious tool name/description patterns
25
+ const SUSPICIOUS_TOOL_DESC = [
26
+ { pattern: /run.*any.*command|execute.*arbitrary|shell.*access/i, desc: "Tool claims unrestricted command execution" },
27
+ { pattern: /access.*all.*files|read.*entire.*filesystem/i, desc: "Tool claims full filesystem access" },
28
+ { pattern: /send.*data.*to|upload.*to|transmit.*to/i, desc: "Tool description mentions data transmission" },
29
+ { pattern: /modify.*system|change.*config/i, desc: "Tool claims system modification capability" },
30
+ ];
31
+ // Dynamic tool loading patterns (runtime tool registration from external sources)
32
+ const DYNAMIC_TOOL_PATTERNS = [
33
+ { pattern: /(?:fetch|axios|got|request)\s*\([^)]*(?:tools|schema|manifest|definition)/i, desc: "Fetches tool definitions from external URL" },
34
+ { pattern: /(?:import|require|load)\s*\([^)]*(?:tool|plugin|extension)\s*(?:url|endpoint|remote)/i, desc: "Dynamically imports tools from remote source" },
35
+ { pattern: /(?:register|add)Tool\s*\(\s*(?:await\s+)?(?:fetch|get|load)/i, desc: "Registers tools loaded from external source" },
36
+ { pattern: /tools\s*=\s*(?:await\s+)?(?:fetch|axios|got)\s*\(/i, desc: "Tool list fetched from remote URL" },
37
+ ];
38
+ export const mcpManifestRule = {
39
+ id: "mcp-manifest",
40
+ name: "MCP Server Validation",
41
+ description: "Validates MCP server tool/resource declarations against actual code behavior",
42
+ run(files) {
43
+ const findings = [];
44
+ // Entity count and config checks work on any JSON with mcpServers
45
+ checkEntityCount(files, findings);
46
+ // Detect if this is an MCP server project for deeper checks
47
+ const isMcpServer = detectMcpServer(files);
48
+ if (!isMcpServer)
49
+ return findings;
50
+ // Check for MCP manifest/config files
51
+ checkMcpConfig(files, findings);
52
+ // Analyze tool implementations for dangerous patterns
53
+ checkToolImplementations(files, findings);
54
+ // Check tool descriptions for suspicious claims
55
+ checkToolDescriptions(files, findings);
56
+ // Check for dynamic tool loading from external sources
57
+ checkDynamicToolLoading(files, findings);
58
+ // Check if tools are registered but have no input validation
59
+ checkInputValidation(files, findings);
60
+ return findings;
61
+ },
62
+ };
63
+ function detectMcpServer(files) {
64
+ for (const file of files) {
65
+ // Check package.json for MCP-related deps
66
+ if (file.relativePath === "package.json") {
67
+ try {
68
+ const pkg = JSON.parse(file.content);
69
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
70
+ if (allDeps["@modelcontextprotocol/sdk"] ||
71
+ allDeps["@anthropic-ai/sdk"] ||
72
+ pkg.mcp) {
73
+ return true;
74
+ }
75
+ }
76
+ catch {
77
+ // ignore parse errors
78
+ }
79
+ }
80
+ // Check for MCP imports in code
81
+ if (file.ext === ".ts" || file.ext === ".js" || file.ext === ".mjs") {
82
+ if (file.content.includes("@modelcontextprotocol/sdk") ||
83
+ file.content.includes("McpServer") ||
84
+ file.content.includes("createMcpServer") ||
85
+ TOOL_REGISTER_RE.test(file.content)) {
86
+ return true;
87
+ }
88
+ }
89
+ // Check for mcp.json or similar config
90
+ if (file.relativePath === "mcp.json" ||
91
+ file.relativePath.endsWith("/mcp.json")) {
92
+ return true;
93
+ }
94
+ }
95
+ return false;
96
+ }
97
+ function checkMcpConfig(files, findings) {
98
+ const mcpConfig = files.find((f) => f.relativePath === "mcp.json" || f.relativePath.endsWith("/mcp.json"));
99
+ if (mcpConfig) {
100
+ try {
101
+ const config = JSON.parse(mcpConfig.content);
102
+ // Check for overly broad permissions
103
+ if (config.permissions) {
104
+ const perms = Array.isArray(config.permissions)
105
+ ? config.permissions
106
+ : Object.keys(config.permissions);
107
+ if (perms.length > 5) {
108
+ findings.push({
109
+ rule: "mcp-manifest",
110
+ severity: "warning",
111
+ file: mcpConfig.relativePath,
112
+ message: `MCP config declares ${perms.length} permissions — consider reducing scope`,
113
+ });
114
+ }
115
+ }
116
+ // Check for wildcard or dangerous permissions
117
+ const configStr = JSON.stringify(config);
118
+ if (configStr.includes('"*"') || configStr.includes('"all"')) {
119
+ findings.push({
120
+ rule: "mcp-manifest",
121
+ severity: "critical",
122
+ file: mcpConfig.relativePath,
123
+ message: "MCP config uses wildcard/all permissions",
124
+ });
125
+ }
126
+ }
127
+ catch {
128
+ findings.push({
129
+ rule: "mcp-manifest",
130
+ severity: "warning",
131
+ file: mcpConfig.relativePath,
132
+ message: "Invalid JSON in MCP config file",
133
+ });
134
+ }
135
+ }
136
+ }
137
+ function checkToolImplementations(files, findings) {
138
+ const codeFiles = files.filter((f) => f.ext === ".ts" || f.ext === ".js" || f.ext === ".mjs" || f.ext === ".cjs");
139
+ for (const file of codeFiles) {
140
+ // Only check files that register tools
141
+ if (!TOOL_REGISTER_RE.test(file.content) && !RESOURCE_REGISTER_RE.test(file.content)) {
142
+ continue;
143
+ }
144
+ for (let i = 0; i < file.lines.length; i++) {
145
+ const line = file.lines[i];
146
+ const trimmed = line.trimStart();
147
+ if (trimmed.startsWith("//") || trimmed.startsWith("*"))
148
+ continue;
149
+ for (const { pattern, desc, severity } of DANGEROUS_TOOL_PATTERNS) {
150
+ if (pattern.test(line)) {
151
+ findings.push({
152
+ rule: "mcp-manifest",
153
+ severity,
154
+ file: file.relativePath,
155
+ line: i + 1,
156
+ message: `MCP tool: ${desc}`,
157
+ evidence: line.trim().slice(0, 120),
158
+ });
159
+ break;
160
+ }
161
+ }
162
+ }
163
+ }
164
+ }
165
+ function checkToolDescriptions(files, findings) {
166
+ const codeFiles = files.filter((f) => f.ext === ".ts" || f.ext === ".js" || f.ext === ".mjs");
167
+ for (const file of codeFiles) {
168
+ // Look for tool description strings
169
+ for (let i = 0; i < file.lines.length; i++) {
170
+ const line = file.lines[i];
171
+ for (const { pattern, desc } of SUSPICIOUS_TOOL_DESC) {
172
+ if (pattern.test(line)) {
173
+ findings.push({
174
+ rule: "mcp-manifest",
175
+ severity: "warning",
176
+ file: file.relativePath,
177
+ line: i + 1,
178
+ message: `Suspicious MCP tool description: ${desc}`,
179
+ evidence: line.trim().slice(0, 120),
180
+ });
181
+ break;
182
+ }
183
+ }
184
+ }
185
+ }
186
+ }
187
+ function checkInputValidation(files, findings) {
188
+ const codeFiles = files.filter((f) => f.ext === ".ts" || f.ext === ".js" || f.ext === ".mjs");
189
+ for (const file of codeFiles) {
190
+ if (!TOOL_REGISTER_RE.test(file.content))
191
+ continue;
192
+ // Check for tools that accept path inputs without validation
193
+ const hasPathInput = /path|file|dir|folder/i.test(file.content);
194
+ const hasPathValidation = /sanitize|validate|allowlist|whitelist|isAbsolute|normalize|resolve/i.test(file.content);
195
+ const hasTraversalCheck = /\.\.\//i.test(file.content) || /path.*traversal/i.test(file.content);
196
+ if (hasPathInput && !hasPathValidation && !hasTraversalCheck) {
197
+ findings.push({
198
+ rule: "mcp-manifest",
199
+ severity: "warning",
200
+ file: file.relativePath,
201
+ message: "MCP tool accepts path inputs but has no visible path validation/sanitization",
202
+ });
203
+ }
204
+ }
205
+ }
206
+ /** Check for dynamic tool loading from external sources */
207
+ function checkDynamicToolLoading(files, findings) {
208
+ const codeFiles = files.filter((f) => f.ext === ".ts" || f.ext === ".js" || f.ext === ".mjs" || f.ext === ".py");
209
+ for (const file of codeFiles) {
210
+ for (let i = 0; i < file.lines.length; i++) {
211
+ const line = file.lines[i];
212
+ const trimmed = line.trimStart();
213
+ if (trimmed.startsWith("//") || trimmed.startsWith("#") || trimmed.startsWith("*"))
214
+ continue;
215
+ for (const { pattern, desc } of DYNAMIC_TOOL_PATTERNS) {
216
+ if (pattern.test(line)) {
217
+ findings.push({
218
+ rule: "mcp-manifest",
219
+ severity: "critical",
220
+ file: file.relativePath,
221
+ line: i + 1,
222
+ message: `Dynamic tool loading: ${desc}`,
223
+ evidence: line.trim().slice(0, 120),
224
+ });
225
+ break;
226
+ }
227
+ }
228
+ }
229
+ }
230
+ }
231
+ /** Check entity count (Snyk W002: too many tools/resources) */
232
+ function checkEntityCount(files, findings) {
233
+ for (const file of files) {
234
+ if (file.ext !== ".json")
235
+ continue;
236
+ try {
237
+ const config = JSON.parse(file.content);
238
+ const servers = config.mcpServers || config.servers || {};
239
+ for (const [serverName, serverConfig] of Object.entries(servers)) {
240
+ if (!serverConfig || typeof serverConfig !== "object")
241
+ continue;
242
+ const sc = serverConfig;
243
+ const tools = Array.isArray(sc.tools) ? sc.tools.length : 0;
244
+ const resources = Array.isArray(sc.resources) ? sc.resources.length : 0;
245
+ const prompts = Array.isArray(sc.prompts) ? sc.prompts.length : 0;
246
+ const total = tools + resources + prompts;
247
+ if (total > 100) {
248
+ findings.push({
249
+ rule: "mcp-manifest",
250
+ severity: "warning",
251
+ file: file.relativePath,
252
+ message: `W002: Server "${serverName}" exposes ${total} entities (${tools} tools, ${resources} resources, ${prompts} prompts) — agent performance may degrade above 100`,
253
+ });
254
+ }
255
+ else if (total > 50) {
256
+ findings.push({
257
+ rule: "mcp-manifest",
258
+ severity: "info",
259
+ file: file.relativePath,
260
+ message: `Server "${serverName}" exposes ${total} entities — consider reducing for optimal agent performance`,
261
+ });
262
+ }
263
+ }
264
+ }
265
+ catch {
266
+ // Not valid JSON
267
+ }
268
+ }
269
+ }
270
+ //# sourceMappingURL=mcp-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-manifest.js","sourceRoot":"","sources":["../../src/rules/mcp-manifest.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AAEH,mDAAmD;AACnD,MAAM,gBAAgB,GACpB,6FAA6F,CAAC;AAEhG,yCAAyC;AACzC,MAAM,oBAAoB,GACxB,iHAAiH,CAAC;AAEpH,6CAA6C;AAC7C,MAAM,uBAAuB,GAA+E;IAC1G,EAAE,OAAO,EAAE,uCAAuC,EAAE,IAAI,EAAE,8BAA8B,EAAE,QAAQ,EAAE,UAAU,EAAE;IAChH,EAAE,OAAO,EAAE,sCAAsC,EAAE,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,SAAS,EAAE;IACpG,EAAE,OAAO,EAAE,oDAAoD,EAAE,IAAI,EAAE,4BAA4B,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC1H,EAAE,OAAO,EAAE,+CAA+C,EAAE,IAAI,EAAE,mCAAmC,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC5H,EAAE,OAAO,EAAE,+BAA+B,EAAE,IAAI,EAAE,kCAAkC,EAAE,QAAQ,EAAE,UAAU,EAAE;IAC5G,EAAE,OAAO,EAAE,yCAAyC,EAAE,IAAI,EAAE,2CAA2C,EAAE,QAAQ,EAAE,UAAU,EAAE;CAChI,CAAC;AAEF,4CAA4C;AAC5C,MAAM,oBAAoB,GAA6C;IACrE,EAAE,OAAO,EAAE,qDAAqD,EAAE,IAAI,EAAE,4CAA4C,EAAE;IACtH,EAAE,OAAO,EAAE,8CAA8C,EAAE,IAAI,EAAE,oCAAoC,EAAE;IACvG,EAAE,OAAO,EAAE,yCAAyC,EAAE,IAAI,EAAE,6CAA6C,EAAE;IAC3G,EAAE,OAAO,EAAE,gCAAgC,EAAE,IAAI,EAAE,4CAA4C,EAAE;CAClG,CAAC;AAEF,kFAAkF;AAClF,MAAM,qBAAqB,GAA6C;IACtE,EAAE,OAAO,EAAE,4EAA4E,EAAE,IAAI,EAAE,4CAA4C,EAAE;IAC7I,EAAE,OAAO,EAAE,uFAAuF,EAAE,IAAI,EAAE,8CAA8C,EAAE;IAC1J,EAAE,OAAO,EAAE,8DAA8D,EAAE,IAAI,EAAE,6CAA6C,EAAE;IAChI,EAAE,OAAO,EAAE,oDAAoD,EAAE,IAAI,EAAE,mCAAmC,EAAE;CAC7G,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAS;IACnC,EAAE,EAAE,cAAc;IAClB,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EAAE,8EAA8E;IAE3F,GAAG,CAAC,KAAoB;QACtB,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,kEAAkE;QAClE,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAElC,4DAA4D;QAC5D,MAAM,WAAW,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,CAAC,WAAW;YAAE,OAAO,QAAQ,CAAC;QAElC,sCAAsC;QACtC,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAEhC,sDAAsD;QACtD,wBAAwB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAE1C,gDAAgD;QAChD,qBAAqB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAEvC,uDAAuD;QACvD,uBAAuB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAEzC,6DAA6D;QAC7D,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAEtC,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC;AAEF,SAAS,eAAe,CAAC,KAAoB;IAC3C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,0CAA0C;QAC1C,IAAI,IAAI,CAAC,YAAY,KAAK,cAAc,EAAE,CAAC;YACzC,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACrC,MAAM,OAAO,GAAG,EAAE,GAAG,GAAG,CAAC,YAAY,EAAE,GAAG,GAAG,CAAC,eAAe,EAAE,CAAC;gBAChE,IACE,OAAO,CAAC,2BAA2B,CAAC;oBACpC,OAAO,CAAC,mBAAmB,CAAC;oBAC5B,GAAG,CAAC,GAAG,EACP,CAAC;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,sBAAsB;YACxB,CAAC;QACH,CAAC;QAED,gCAAgC;QAChC,IAAI,IAAI,CAAC,GAAG,KAAK,KAAK,IAAI,IAAI,CAAC,GAAG,KAAK,KAAK,IAAI,IAAI,CAAC,GAAG,KAAK,MAAM,EAAE,CAAC;YACpE,IACE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC;gBAClD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;gBAClC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;gBACxC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EACnC,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,uCAAuC;QACvC,IACE,IAAI,CAAC,YAAY,KAAK,UAAU;YAChC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,EACvC,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,cAAc,CAAC,KAAoB,EAAE,QAAmB;IAC/D,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAC1B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,UAAU,IAAI,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,CAC7E,CAAC;IAEF,IAAI,SAAS,EAAE,CAAC;QACd,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAE7C,qCAAqC;YACrC,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;gBACvB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC;oBAC7C,CAAC,CAAC,MAAM,CAAC,WAAW;oBACpB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;gBACpC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,QAAQ,CAAC,IAAI,CAAC;wBACZ,IAAI,EAAE,cAAc;wBACpB,QAAQ,EAAE,SAAS;wBACnB,IAAI,EAAE,SAAS,CAAC,YAAY;wBAC5B,OAAO,EAAE,uBAAuB,KAAK,CAAC,MAAM,wCAAwC;qBACrF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAED,8CAA8C;YAC9C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC7D,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,cAAc;oBACpB,QAAQ,EAAE,UAAU;oBACpB,IAAI,EAAE,SAAS,CAAC,YAAY;oBAC5B,OAAO,EAAE,0CAA0C;iBACpD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,SAAS;gBACnB,IAAI,EAAE,SAAS,CAAC,YAAY;gBAC5B,OAAO,EAAE,iCAAiC;aAC3C,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,wBAAwB,CAAC,KAAoB,EAAE,QAAmB;IACzE,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAC5B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,GAAG,KAAK,MAAM,IAAI,CAAC,CAAC,GAAG,KAAK,MAAM,CAClF,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,uCAAuC;QACvC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACrF,SAAS;QACX,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC;YAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;YACjC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAS;YAElE,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,uBAAuB,EAAE,CAAC;gBAClE,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACvB,QAAQ,CAAC,IAAI,CAAC;wBACZ,IAAI,EAAE,cAAc;wBACpB,QAAQ;wBACR,IAAI,EAAE,IAAI,CAAC,YAAY;wBACvB,IAAI,EAAE,CAAC,GAAG,CAAC;wBACX,OAAO,EAAE,aAAa,IAAI,EAAE;wBAC5B,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;qBACpC,CAAC,CAAC;oBACH,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAoB,EAAE,QAAmB;IACtE,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAC5B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,GAAG,KAAK,MAAM,CAC9D,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,oCAAoC;QACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC;YAE5B,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,oBAAoB,EAAE,CAAC;gBACrD,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACvB,QAAQ,CAAC,IAAI,CAAC;wBACZ,IAAI,EAAE,cAAc;wBACpB,QAAQ,EAAE,SAAS;wBACnB,IAAI,EAAE,IAAI,CAAC,YAAY;wBACvB,IAAI,EAAE,CAAC,GAAG,CAAC;wBACX,OAAO,EAAE,oCAAoC,IAAI,EAAE;wBACnD,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;qBACpC,CAAC,CAAC;oBACH,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAoB,EAAE,QAAmB;IACrE,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAC5B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,GAAG,KAAK,MAAM,CAC9D,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,SAAS;QAEnD,6DAA6D;QAC7D,MAAM,YAAY,GAAG,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChE,MAAM,iBAAiB,GAAG,qEAAqE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnH,MAAM,iBAAiB,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEhG,IAAI,YAAY,IAAI,CAAC,iBAAiB,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC7D,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,SAAS;gBACnB,IAAI,EAAE,IAAI,CAAC,YAAY;gBACvB,OAAO,EAAE,8EAA8E;aACxF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAED,2DAA2D;AAC3D,SAAS,uBAAuB,CAAC,KAAoB,EAAE,QAAmB;IACxE,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAC5B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,GAAG,KAAK,MAAM,IAAI,CAAC,CAAC,GAAG,KAAK,KAAK,CACjF,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC;YAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;YACjC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAS;YAE7F,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,qBAAqB,EAAE,CAAC;gBACtD,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACvB,QAAQ,CAAC,IAAI,CAAC;wBACZ,IAAI,EAAE,cAAc;wBACpB,QAAQ,EAAE,UAAU;wBACpB,IAAI,EAAE,IAAI,CAAC,YAAY;wBACvB,IAAI,EAAE,CAAC,GAAG,CAAC;wBACX,OAAO,EAAE,yBAAyB,IAAI,EAAE;wBACxC,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;qBACpC,CAAC,CAAC;oBACH,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,+DAA+D;AAC/D,SAAS,gBAAgB,CAAC,KAAoB,EAAE,QAAmB;IACjE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,GAAG,KAAK,OAAO;YAAE,SAAS;QACnC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACxC,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;YAE1D,KAAK,MAAM,CAAC,UAAU,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gBACjE,IAAI,CAAC,YAAY,IAAI,OAAO,YAAY,KAAK,QAAQ;oBAAE,SAAS;gBAChE,MAAM,EAAE,GAAG,YAAuC,CAAC;gBACnD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC5D,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBACxE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAClE,MAAM,KAAK,GAAG,KAAK,GAAG,SAAS,GAAG,OAAO,CAAC;gBAE1C,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;oBAChB,QAAQ,CAAC,IAAI,CAAC;wBACZ,IAAI,EAAE,cAAc;wBACpB,QAAQ,EAAE,SAAS;wBACnB,IAAI,EAAE,IAAI,CAAC,YAAY;wBACvB,OAAO,EAAE,iBAAiB,UAAU,aAAa,KAAK,cAAc,KAAK,WAAW,SAAS,eAAe,OAAO,qDAAqD;qBACzK,CAAC,CAAC;gBACL,CAAC;qBAAM,IAAI,KAAK,GAAG,EAAE,EAAE,CAAC;oBACtB,QAAQ,CAAC,IAAI,CAAC;wBACZ,IAAI,EAAE,cAAc;wBACpB,QAAQ,EAAE,MAAM;wBAChB,IAAI,EAAE,IAAI,CAAC,YAAY;wBACvB,OAAO,EAAE,WAAW,UAAU,aAAa,KAAK,6DAA6D;qBAC9G,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,iBAAiB;QACnB,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Rule } from "../types.js";
2
+ export declare const networkSsrfRule: Rule;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Rule: network-ssrf
3
+ * Detects Server-Side Request Forgery patterns — user-controlled URLs in HTTP requests.
4
+ */
5
+ const SSRF_PATTERNS = [
6
+ // Template literals in fetch/request
7
+ { pattern: /fetch\s*\(\s*`[^`]*\$\{/, desc: "fetch() with template literal URL — potential SSRF", severity: "warning" },
8
+ { pattern: /axios\.\w+\s*\(\s*`[^`]*\$\{/, desc: "axios with template literal URL — potential SSRF", severity: "warning" },
9
+ { pattern: /http\.request\s*\(\s*`[^`]*\$\{/, desc: "http.request with template literal URL — potential SSRF", severity: "warning" },
10
+ // URL constructed from user input
11
+ { pattern: /new\s+URL\s*\(\s*(?:req\.|request\.|params\.|query\.|body\.)/, desc: "URL from request parameters — potential SSRF", severity: "critical" },
12
+ { pattern: /fetch\s*\(\s*(?:req\.|request\.|params\.|query\.|body\.)/, desc: "fetch() with request parameter — potential SSRF", severity: "critical" },
13
+ // Redirect to user-controlled URL
14
+ { pattern: /redirect\s*\(\s*(?:req\.|request\.|params\.|query\.)/, desc: "Open redirect — user-controlled redirect URL", severity: "warning" },
15
+ // Internal network access patterns
16
+ { pattern: /127\.0\.0\.1|0\.0\.0\.0|localhost.*fetch|fetch.*localhost/i, desc: "Request to localhost — verify if intentional", severity: "warning" },
17
+ { pattern: /169\.254\.169\.254/, desc: "AWS metadata endpoint access — potential SSRF", severity: "critical" },
18
+ ];
19
+ export const networkSsrfRule = {
20
+ id: "network-ssrf",
21
+ name: "Server-Side Request Forgery",
22
+ description: "Detects user-controlled URLs in HTTP requests and internal network access",
23
+ run(files) {
24
+ const findings = [];
25
+ for (const file of files) {
26
+ if (file.ext === ".json" || file.ext === ".yaml" || file.ext === ".yml" || file.ext === ".md")
27
+ continue;
28
+ for (let i = 0; i < file.lines.length; i++) {
29
+ const line = file.lines[i];
30
+ const trimmed = line.trimStart();
31
+ if (trimmed.startsWith("//") || trimmed.startsWith("#"))
32
+ continue;
33
+ for (const { pattern, desc, severity } of SSRF_PATTERNS) {
34
+ if (pattern.test(line)) {
35
+ findings.push({
36
+ rule: "network-ssrf",
37
+ severity,
38
+ file: file.relativePath,
39
+ line: i + 1,
40
+ message: desc,
41
+ evidence: line.trim().slice(0, 120),
42
+ });
43
+ break;
44
+ }
45
+ }
46
+ }
47
+ }
48
+ return findings;
49
+ },
50
+ };
51
+ //# sourceMappingURL=network-ssrf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network-ssrf.js","sourceRoot":"","sources":["../../src/rules/network-ssrf.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,MAAM,aAAa,GAA+E;IAChG,qCAAqC;IACrC,EAAE,OAAO,EAAE,yBAAyB,EAAE,IAAI,EAAE,oDAAoD,EAAE,QAAQ,EAAE,SAAS,EAAE;IACvH,EAAE,OAAO,EAAE,8BAA8B,EAAE,IAAI,EAAE,kDAAkD,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC1H,EAAE,OAAO,EAAE,iCAAiC,EAAE,IAAI,EAAE,yDAAyD,EAAE,QAAQ,EAAE,SAAS,EAAE;IACpI,kCAAkC;IAClC,EAAE,OAAO,EAAE,8DAA8D,EAAE,IAAI,EAAE,8CAA8C,EAAE,QAAQ,EAAE,UAAU,EAAE;IACvJ,EAAE,OAAO,EAAE,0DAA0D,EAAE,IAAI,EAAE,iDAAiD,EAAE,QAAQ,EAAE,UAAU,EAAE;IACtJ,kCAAkC;IAClC,EAAE,OAAO,EAAE,sDAAsD,EAAE,IAAI,EAAE,8CAA8C,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC9I,mCAAmC;IACnC,EAAE,OAAO,EAAE,4DAA4D,EAAE,IAAI,EAAE,8CAA8C,EAAE,QAAQ,EAAE,SAAS,EAAE;IACpJ,EAAE,OAAO,EAAE,oBAAoB,EAAE,IAAI,EAAE,+CAA+C,EAAE,QAAQ,EAAE,UAAU,EAAE;CAC/G,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAS;IACnC,EAAE,EAAE,cAAc;IAClB,IAAI,EAAE,6BAA6B;IACnC,WAAW,EAAE,2EAA2E;IAExF,GAAG,CAAC,KAAoB;QACtB,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,GAAG,KAAK,OAAO,IAAI,IAAI,CAAC,GAAG,KAAK,OAAO,IAAI,IAAI,CAAC,GAAG,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,KAAK,KAAK;gBAAE,SAAS;YAExG,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC;gBAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;gBACjC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;oBAAE,SAAS;gBAElE,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,aAAa,EAAE,CAAC;oBACxD,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;wBACvB,QAAQ,CAAC,IAAI,CAAC;4BACZ,IAAI,EAAE,cAAc;4BACpB,QAAQ;4BACR,IAAI,EAAE,IAAI,CAAC,YAAY;4BACvB,IAAI,EAAE,CAAC,GAAG,CAAC;4BACX,OAAO,EAAE,IAAI;4BACb,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;yBACpC,CAAC,CAAC;wBACH,MAAM;oBACR,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Rule } from "../types.js";
2
+ export declare const obfuscationRule: Rule;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Rule: obfuscation
3
+ * Detects base64 decoding + eval/exec combos and other obfuscation patterns.
4
+ */
5
+ const OBFUSCATION_PATTERNS = [
6
+ { pattern: /atob\s*\(.*\beval\b|eval\s*\(.*\batob\b/, desc: "atob() + eval() combo", severity: "critical" },
7
+ { pattern: /Buffer\.from\s*\([^)]*,\s*["']base64["']\).*\beval\b/, desc: "Base64 decode + eval()", severity: "critical" },
8
+ { pattern: /Buffer\.from\s*\([^)]*,\s*["']base64["']\).*\bexec\b/, desc: "Base64 decode + exec()", severity: "critical" },
9
+ { pattern: /\bString\.fromCharCode\s*\(/, desc: "String.fromCharCode() — potential obfuscation", severity: "warning" },
10
+ { pattern: /\\x[0-9a-f]{2}\\x[0-9a-f]{2}\\x[0-9a-f]{2}/, desc: "Hex-encoded string sequence", severity: "warning" },
11
+ { pattern: /\\u00[0-9a-f]{2}\\u00[0-9a-f]{2}/, desc: "Unicode-escaped string sequence", severity: "warning" },
12
+ ];
13
+ export const obfuscationRule = {
14
+ id: "obfuscation",
15
+ name: "Code Obfuscation",
16
+ description: "Detects base64+eval combos, hex encoding, and other obfuscation techniques",
17
+ run(files) {
18
+ const findings = [];
19
+ for (const file of files) {
20
+ if (file.ext === ".json" || file.ext === ".yaml" || file.ext === ".yml" || file.ext === ".md")
21
+ continue;
22
+ // Check multi-line patterns across entire content
23
+ for (const { pattern, desc, severity } of OBFUSCATION_PATTERNS.slice(0, 3)) {
24
+ if (pattern.test(file.content)) {
25
+ // Find the line with eval/exec
26
+ for (let i = 0; i < file.lines.length; i++) {
27
+ if (/\beval\b|\bexec\b/.test(file.lines[i])) {
28
+ findings.push({ rule: "obfuscation", severity, file: file.relativePath, line: i + 1, message: desc, evidence: file.lines[i].trim().slice(0, 120) });
29
+ break;
30
+ }
31
+ }
32
+ }
33
+ }
34
+ // Per-line patterns
35
+ for (let i = 0; i < file.lines.length; i++) {
36
+ const line = file.lines[i];
37
+ const trimmed = line.trimStart();
38
+ if (trimmed.startsWith("//") || trimmed.startsWith("#"))
39
+ continue;
40
+ for (const { pattern, desc, severity } of OBFUSCATION_PATTERNS.slice(3)) {
41
+ if (pattern.test(line)) {
42
+ findings.push({ rule: "obfuscation", severity, file: file.relativePath, line: i + 1, message: desc, evidence: line.trim().slice(0, 120) });
43
+ break;
44
+ }
45
+ }
46
+ }
47
+ }
48
+ return findings;
49
+ },
50
+ };
51
+ //# sourceMappingURL=obfuscation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"obfuscation.js","sourceRoot":"","sources":["../../src/rules/obfuscation.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,MAAM,oBAAoB,GAIrB;IACH,EAAE,OAAO,EAAE,yCAAyC,EAAE,IAAI,EAAE,uBAAuB,EAAE,QAAQ,EAAE,UAAU,EAAE;IAC3G,EAAE,OAAO,EAAE,sDAAsD,EAAE,IAAI,EAAE,wBAAwB,EAAE,QAAQ,EAAE,UAAU,EAAE;IACzH,EAAE,OAAO,EAAE,sDAAsD,EAAE,IAAI,EAAE,wBAAwB,EAAE,QAAQ,EAAE,UAAU,EAAE;IACzH,EAAE,OAAO,EAAE,6BAA6B,EAAE,IAAI,EAAE,+CAA+C,EAAE,QAAQ,EAAE,SAAS,EAAE;IACtH,EAAE,OAAO,EAAE,4CAA4C,EAAE,IAAI,EAAE,6BAA6B,EAAE,QAAQ,EAAE,SAAS,EAAE;IACnH,EAAE,OAAO,EAAE,kCAAkC,EAAE,IAAI,EAAE,iCAAiC,EAAE,QAAQ,EAAE,SAAS,EAAE;CAC9G,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAS;IACnC,EAAE,EAAE,aAAa;IACjB,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,4EAA4E;IAEzF,GAAG,CAAC,KAAoB;QACtB,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,GAAG,KAAK,OAAO,IAAI,IAAI,CAAC,GAAG,KAAK,OAAO,IAAI,IAAI,CAAC,GAAG,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,KAAK,KAAK;gBAAE,SAAS;YAExG,kDAAkD;YAClD,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,oBAAoB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBAC3E,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC/B,+BAA+B;oBAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;wBAC3C,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC;4BAC7C,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;4BACrJ,MAAM;wBACR,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YAED,oBAAoB;YACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC;gBAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;gBACjC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;oBAAE,SAAS;gBAElE,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;oBACxE,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;wBACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;wBAC3I,MAAM;oBACR,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Rule } from "../types.js";
2
+ export declare const phoneHomeRule: Rule;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Rule: phone-home
3
+ * Detects periodic timers combined with HTTP requests — "calling home" patterns.
4
+ */
5
+ const TIMER_RE = /setInterval\s*\(|cron\s*\(|schedule\s*\(|setTimeout.*setInterval|recurring|periodic/i;
6
+ const HTTP_RE = /fetch\s*\(|axios\.|http\.request|https\.request|\.post\s*\(|\.get\s*\(/i;
7
+ export const phoneHomeRule = {
8
+ id: "phone-home",
9
+ name: "Phone Home / Beacon",
10
+ description: "Detects periodic timers combined with HTTP requests (heartbeat/beacon pattern)",
11
+ run(files) {
12
+ const findings = [];
13
+ for (const file of files) {
14
+ if (file.ext === ".json" || file.ext === ".yaml" || file.ext === ".yml" || file.ext === ".md")
15
+ continue;
16
+ const hasTimer = TIMER_RE.test(file.content);
17
+ const hasHttp = HTTP_RE.test(file.content);
18
+ if (hasTimer && hasHttp) {
19
+ // Find the timer line
20
+ for (let i = 0; i < file.lines.length; i++) {
21
+ if (TIMER_RE.test(file.lines[i])) {
22
+ findings.push({
23
+ rule: "phone-home",
24
+ severity: "warning",
25
+ file: file.relativePath,
26
+ line: i + 1,
27
+ message: "Periodic timer + HTTP request — possible beacon/phone-home pattern",
28
+ evidence: file.lines[i].trim().slice(0, 120),
29
+ });
30
+ break;
31
+ }
32
+ }
33
+ }
34
+ }
35
+ return findings;
36
+ },
37
+ };
38
+ //# sourceMappingURL=phone-home.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phone-home.js","sourceRoot":"","sources":["../../src/rules/phone-home.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,MAAM,QAAQ,GAAG,sFAAsF,CAAC;AACxG,MAAM,OAAO,GAAG,yEAAyE,CAAC;AAE1F,MAAM,CAAC,MAAM,aAAa,GAAS;IACjC,EAAE,EAAE,YAAY;IAChB,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EAAE,gFAAgF;IAE7F,GAAG,CAAC,KAAoB;QACtB,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,GAAG,KAAK,OAAO,IAAI,IAAI,CAAC,GAAG,KAAK,OAAO,IAAI,IAAI,CAAC,GAAG,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,KAAK,KAAK;gBAAE,SAAS;YAExG,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC7C,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE3C,IAAI,QAAQ,IAAI,OAAO,EAAE,CAAC;gBACxB,sBAAsB;gBACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC3C,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC;wBAClC,QAAQ,CAAC,IAAI,CAAC;4BACZ,IAAI,EAAE,YAAY;4BAClB,QAAQ,EAAE,SAAS;4BACnB,IAAI,EAAE,IAAI,CAAC,YAAY;4BACvB,IAAI,EAAE,CAAC,GAAG,CAAC;4BACX,OAAO,EAAE,oEAAoE;4BAC7E,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;yBAC9C,CAAC,CAAC;wBACH,MAAM;oBACR,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Rule } from "../types.js";
2
+ export declare const privilegeRule: Rule;
@@ -0,0 +1,111 @@
1
+ import matter from "gray-matter";
2
+ /**
3
+ * Rule: privilege
4
+ * Compares declared permissions in SKILL.md vs actual API usage in code.
5
+ */
6
+ // Map of capabilities to code patterns that indicate their use
7
+ const CAPABILITY_PATTERNS = {
8
+ exec: /child_process|execSync|exec\(|spawn\(|os\.system|subprocess|ShellAction/i,
9
+ read: /readFile|readFileSync|fs\.read|open\(.*["']r/i,
10
+ write: /writeFile|writeFileSync|fs\.write|appendFile|open\(.*["']w/i,
11
+ web_fetch: /fetch\s*\(|axios|http\.request|https\.request|requests\.(get|post)/i,
12
+ browser: /puppeteer|playwright|selenium|webdriver|BrowserAction/i,
13
+ network: /net\.connect|dgram|WebSocket|Socket/i,
14
+ };
15
+ export const privilegeRule = {
16
+ id: "privilege",
17
+ name: "Privilege Mismatch",
18
+ description: "Compares declared permissions in SKILL.md against actual code behavior",
19
+ run(files) {
20
+ const findings = [];
21
+ // Find SKILL.md
22
+ const skillMd = files.find((f) => f.relativePath === "SKILL.md" || f.relativePath.endsWith("/SKILL.md"));
23
+ if (!skillMd) {
24
+ // No SKILL.md — can't check permissions
25
+ findings.push({
26
+ rule: "privilege",
27
+ severity: "info",
28
+ file: ".",
29
+ message: "No SKILL.md found — permission analysis skipped",
30
+ });
31
+ return findings;
32
+ }
33
+ // Parse frontmatter
34
+ let meta = {};
35
+ try {
36
+ const { data } = matter(skillMd.content);
37
+ meta = data;
38
+ }
39
+ catch {
40
+ // not valid frontmatter
41
+ }
42
+ // Extract declared permissions (from frontmatter or body)
43
+ const declaredPerms = new Set();
44
+ if (Array.isArray(meta.permissions)) {
45
+ for (const p of meta.permissions) {
46
+ if (typeof p === "string")
47
+ declaredPerms.add(p.toLowerCase());
48
+ }
49
+ }
50
+ // Also scan SKILL.md body for permission keywords
51
+ const bodyPermsMatch = skillMd.content.match(/permissions?:\s*([\w,\s]+)/i);
52
+ if (bodyPermsMatch) {
53
+ for (const p of bodyPermsMatch[1].split(/[,\s]+/)) {
54
+ if (p.trim())
55
+ declaredPerms.add(p.trim().toLowerCase());
56
+ }
57
+ }
58
+ // Scan code files for actual capability usage
59
+ const codeFiles = files.filter((f) => f.ext !== ".md" && f.ext !== ".json" && f.ext !== ".yaml" && f.ext !== ".yml");
60
+ const usedCapabilities = new Set();
61
+ const capabilityLocations = {};
62
+ for (const file of codeFiles) {
63
+ for (const [cap, pattern] of Object.entries(CAPABILITY_PATTERNS)) {
64
+ for (let i = 0; i < file.lines.length; i++) {
65
+ if (pattern.test(file.lines[i])) {
66
+ usedCapabilities.add(cap);
67
+ if (!capabilityLocations[cap])
68
+ capabilityLocations[cap] = [];
69
+ capabilityLocations[cap].push({ file: file.relativePath, line: i + 1 });
70
+ }
71
+ }
72
+ }
73
+ }
74
+ // Report undeclared capabilities
75
+ for (const cap of usedCapabilities) {
76
+ if (declaredPerms.size > 0 && !declaredPerms.has(cap)) {
77
+ const locations = capabilityLocations[cap] || [];
78
+ const first = locations[0];
79
+ findings.push({
80
+ rule: "privilege",
81
+ severity: "warning",
82
+ file: first?.file || skillMd.relativePath,
83
+ line: first?.line,
84
+ message: `Code uses '${cap}' capability but SKILL.md doesn't declare it (found in ${locations.length} location${locations.length > 1 ? "s" : ""})`,
85
+ });
86
+ }
87
+ }
88
+ // Report declared but unused permissions
89
+ for (const perm of declaredPerms) {
90
+ if (!usedCapabilities.has(perm) && CAPABILITY_PATTERNS[perm]) {
91
+ findings.push({
92
+ rule: "privilege",
93
+ severity: "info",
94
+ file: skillMd.relativePath,
95
+ message: `SKILL.md declares '${perm}' permission but code doesn't appear to use it`,
96
+ });
97
+ }
98
+ }
99
+ // Report used capabilities as info
100
+ if (usedCapabilities.size > 0) {
101
+ findings.push({
102
+ rule: "privilege",
103
+ severity: "info",
104
+ file: skillMd.relativePath,
105
+ message: `Detected capabilities: ${[...usedCapabilities].join(", ")}`,
106
+ });
107
+ }
108
+ return findings;
109
+ },
110
+ };
111
+ //# sourceMappingURL=privilege.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"privilege.js","sourceRoot":"","sources":["../../src/rules/privilege.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Rule } from "../types.js";
2
+ export declare const promptInjection: Rule;