acidtest 0.1.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/LICENSE +21 -0
- package/README.md +104 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +170 -0
- package/dist/index.js.map +1 -0
- package/dist/layers/code.d.ts +10 -0
- package/dist/layers/code.d.ts.map +1 -0
- package/dist/layers/code.js +196 -0
- package/dist/layers/code.js.map +1 -0
- package/dist/layers/crossref.d.ts +10 -0
- package/dist/layers/crossref.d.ts.map +1 -0
- package/dist/layers/crossref.js +143 -0
- package/dist/layers/crossref.js.map +1 -0
- package/dist/layers/injection.d.ts +10 -0
- package/dist/layers/injection.d.ts.map +1 -0
- package/dist/layers/injection.js +88 -0
- package/dist/layers/injection.js.map +1 -0
- package/dist/layers/permissions.d.ts +10 -0
- package/dist/layers/permissions.d.ts.map +1 -0
- package/dist/layers/permissions.js +120 -0
- package/dist/layers/permissions.js.map +1 -0
- package/dist/pattern-loader.d.ts +14 -0
- package/dist/pattern-loader.d.ts.map +1 -0
- package/dist/pattern-loader.js +50 -0
- package/dist/pattern-loader.js.map +1 -0
- package/dist/patterns/credential-patterns.json +77 -0
- package/dist/patterns/dangerous-imports.json +113 -0
- package/dist/patterns/exfiltration-sinks.json +77 -0
- package/dist/patterns/obfuscation.json +65 -0
- package/dist/patterns/prompt-injection.json +125 -0
- package/dist/patterns/sensitive-paths.json +89 -0
- package/dist/reporter.d.ts +14 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +175 -0
- package/dist/reporter.js.map +1 -0
- package/dist/scanner.d.ts +15 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +176 -0
- package/dist/scanner.js.map +1 -0
- package/dist/scoring.d.ts +23 -0
- package/dist/scoring.d.ts.map +1 -0
- package/dist/scoring.js +85 -0
- package/dist/scoring.js.map +1 -0
- package/dist/types.d.ts +112 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 4: Cross-Reference Analysis
|
|
3
|
+
* Compares findings across layers to detect permission mismatches and deception
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Cross-reference findings from previous layers
|
|
7
|
+
*/
|
|
8
|
+
export async function scanCrossReference(skill, previousFindings) {
|
|
9
|
+
const findings = [];
|
|
10
|
+
const metadata = skill.metadata;
|
|
11
|
+
// Extract findings by category
|
|
12
|
+
const networkFindings = previousFindings.filter(f => f.category.includes('network') ||
|
|
13
|
+
f.category === 'exfiltration-sinks' ||
|
|
14
|
+
f.patternId?.startsWith('ex-'));
|
|
15
|
+
const shellFindings = previousFindings.filter(f => f.category.includes('child_process') ||
|
|
16
|
+
f.category.includes('shell') ||
|
|
17
|
+
f.patternId === 'di-001');
|
|
18
|
+
const fileSystemFindings = previousFindings.filter(f => f.category.includes('filesystem') ||
|
|
19
|
+
f.category.includes('sensitive-paths') ||
|
|
20
|
+
f.patternId?.startsWith('sp-'));
|
|
21
|
+
const envAccessFindings = previousFindings.filter(f => f.patternId === 'cp-006' // process.env access
|
|
22
|
+
);
|
|
23
|
+
// Get declared permissions
|
|
24
|
+
const allowedTools = metadata['allowed-tools'] || [];
|
|
25
|
+
const allowedBins = metadata.bins || [];
|
|
26
|
+
const allowedEnv = metadata.env || [];
|
|
27
|
+
// Check for network capability mismatches
|
|
28
|
+
if (networkFindings.length > 0) {
|
|
29
|
+
const declaredNetwork = allowedTools.some(tool => ['browser', 'http', 'fetch', 'network', 'web', 'curl', 'wget'].some(net => tool.toLowerCase().includes(net))) || allowedBins.some(bin => ['curl', 'wget'].some(net => bin.toLowerCase().includes(net)));
|
|
30
|
+
if (!declaredNetwork) {
|
|
31
|
+
findings.push({
|
|
32
|
+
severity: 'CRITICAL',
|
|
33
|
+
category: 'permission-mismatch',
|
|
34
|
+
title: 'Undeclared network access',
|
|
35
|
+
detail: 'Code makes network calls but skill does not declare network permissions',
|
|
36
|
+
evidence: `Found ${networkFindings.length} network-related finding(s) in code`
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Check for shell execution mismatches
|
|
41
|
+
if (shellFindings.length > 0) {
|
|
42
|
+
const declaredShell = allowedTools.some(tool => ['shell', 'bash', 'exec', 'command'].some(sh => tool.toLowerCase().includes(sh))) || allowedBins.some(bin => ['bash', 'sh', 'zsh', 'fish', 'cmd', 'powershell'].some(sh => bin.toLowerCase() === sh));
|
|
43
|
+
if (!declaredShell) {
|
|
44
|
+
findings.push({
|
|
45
|
+
severity: 'CRITICAL',
|
|
46
|
+
category: 'permission-mismatch',
|
|
47
|
+
title: 'Undeclared shell execution',
|
|
48
|
+
detail: 'Code executes shell commands but skill does not declare shell permissions',
|
|
49
|
+
evidence: `Found ${shellFindings.length} shell-related finding(s) in code`
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Check for file system access mismatches
|
|
54
|
+
if (fileSystemFindings.length > 0) {
|
|
55
|
+
const declaredFS = allowedTools.some(tool => ['file', 'filesystem', 'fs', 'read', 'write'].some(fs => tool.toLowerCase().includes(fs)));
|
|
56
|
+
if (!declaredFS) {
|
|
57
|
+
findings.push({
|
|
58
|
+
severity: 'HIGH',
|
|
59
|
+
category: 'permission-mismatch',
|
|
60
|
+
title: 'Undeclared file system access',
|
|
61
|
+
detail: 'Code accesses sensitive file paths but skill does not declare filesystem permissions',
|
|
62
|
+
evidence: `Found ${fileSystemFindings.length} filesystem-related finding(s) in code`
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Check for environment variable mismatches
|
|
67
|
+
if (envAccessFindings.length > 0 && skill.codeFiles.length > 0) {
|
|
68
|
+
// Extract environment variables accessed in code
|
|
69
|
+
const codeEnvVars = extractEnvVarsFromCode(skill.codeFiles);
|
|
70
|
+
// Find undeclared env vars
|
|
71
|
+
const undeclaredEnvVars = codeEnvVars.filter(envVar => !allowedEnv.includes(envVar));
|
|
72
|
+
if (undeclaredEnvVars.length > 0) {
|
|
73
|
+
findings.push({
|
|
74
|
+
severity: 'HIGH',
|
|
75
|
+
category: 'permission-mismatch',
|
|
76
|
+
title: 'Undeclared environment variable access',
|
|
77
|
+
detail: 'Code accesses environment variables not declared in skill metadata',
|
|
78
|
+
evidence: `Undeclared variables: ${undeclaredEnvVars.slice(0, 5).join(', ')}${undeclaredEnvVars.length > 5 ? '...' : ''}`
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Check for deception indicators
|
|
83
|
+
const description = (metadata.description || '').toLowerCase();
|
|
84
|
+
const benignKeywords = ['calculator', 'timer', 'note', 'reminder', 'formatter', 'converter'];
|
|
85
|
+
const seemsBenign = benignKeywords.some(kw => description.includes(kw));
|
|
86
|
+
if (seemsBenign && networkFindings.length > 0) {
|
|
87
|
+
findings.push({
|
|
88
|
+
severity: 'HIGH',
|
|
89
|
+
category: 'deception-indicator',
|
|
90
|
+
title: 'Benign description with network access',
|
|
91
|
+
detail: `Skill claims to be a "${metadata.description}" but makes network calls`,
|
|
92
|
+
evidence: 'Simple utility skills typically do not require network access'
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// Check for supply chain indicators
|
|
96
|
+
if (skill.codeFiles.length > 0) {
|
|
97
|
+
// Check for suspiciously large code files for simple functionality
|
|
98
|
+
const totalCodeSize = skill.codeFiles.reduce((sum, f) => sum + f.content.length, 0);
|
|
99
|
+
if (totalCodeSize > 100000 && seemsBenign) {
|
|
100
|
+
findings.push({
|
|
101
|
+
severity: 'MEDIUM',
|
|
102
|
+
category: 'supply-chain-risk',
|
|
103
|
+
title: 'Unusually large code for stated purpose',
|
|
104
|
+
detail: `Code is ${totalCodeSize} characters but skill description suggests simple functionality`,
|
|
105
|
+
evidence: 'Large code size may indicate hidden functionality'
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
// Check for minified code
|
|
109
|
+
const hasMinified = skill.codeFiles.some(f => {
|
|
110
|
+
const lines = f.content.split('\n');
|
|
111
|
+
const avgLineLength = f.content.length / lines.length;
|
|
112
|
+
return avgLineLength > 200; // Average line > 200 chars suggests minification
|
|
113
|
+
});
|
|
114
|
+
if (hasMinified) {
|
|
115
|
+
findings.push({
|
|
116
|
+
severity: 'MEDIUM',
|
|
117
|
+
category: 'supply-chain-risk',
|
|
118
|
+
title: 'Minified or obfuscated code detected',
|
|
119
|
+
detail: 'Code appears to be minified or obfuscated',
|
|
120
|
+
evidence: 'Minified code is harder to audit and may hide malicious behavior'
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
layer: 'crossref',
|
|
126
|
+
findings
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Extract environment variable names accessed in code
|
|
131
|
+
*/
|
|
132
|
+
function extractEnvVarsFromCode(codeFiles) {
|
|
133
|
+
const envVars = new Set();
|
|
134
|
+
const envPattern = /process\.env\.([A-Z_][A-Z0-9_]*)/g;
|
|
135
|
+
for (const file of codeFiles) {
|
|
136
|
+
let match;
|
|
137
|
+
while ((match = envPattern.exec(file.content)) !== null) {
|
|
138
|
+
envVars.add(match[1]);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return Array.from(envVars);
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=crossref.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crossref.js","sourceRoot":"","sources":["../../src/layers/crossref.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 2: Prompt Injection Scan
|
|
3
|
+
* Scans markdown content for prompt injection patterns
|
|
4
|
+
*/
|
|
5
|
+
import type { Skill, LayerResult } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Scan markdown content for prompt injection patterns
|
|
8
|
+
*/
|
|
9
|
+
export declare function scanInjection(skill: Skill): Promise<LayerResult>;
|
|
10
|
+
//# sourceMappingURL=injection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injection.d.ts","sourceRoot":"","sources":["../../src/layers/injection.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAW,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/D;;GAEG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC,CAmEtE"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 2: Prompt Injection Scan
|
|
3
|
+
* Scans markdown content for prompt injection patterns
|
|
4
|
+
*/
|
|
5
|
+
import { loadPatterns } from '../pattern-loader.js';
|
|
6
|
+
/**
|
|
7
|
+
* Scan markdown content for prompt injection patterns
|
|
8
|
+
*/
|
|
9
|
+
export async function scanInjection(skill) {
|
|
10
|
+
const findings = [];
|
|
11
|
+
const markdown = skill.markdownContent;
|
|
12
|
+
// Load prompt injection and sensitive path patterns
|
|
13
|
+
const promptPatterns = await loadPatterns('prompt-injection');
|
|
14
|
+
const pathPatterns = await loadPatterns('sensitive-paths');
|
|
15
|
+
// Combine patterns that apply to markdown layer
|
|
16
|
+
const allPatterns = [...promptPatterns, ...pathPatterns].filter(p => p.layer === 'markdown');
|
|
17
|
+
// Scan against each pattern
|
|
18
|
+
for (const pattern of allPatterns) {
|
|
19
|
+
const regex = new RegExp(pattern.match.value, pattern.match.flags || '');
|
|
20
|
+
const matches = markdown.match(regex);
|
|
21
|
+
if (matches && matches.length > 0) {
|
|
22
|
+
// Try to find line number for the match
|
|
23
|
+
const lineNumber = findLineNumber(markdown, matches[0]);
|
|
24
|
+
findings.push({
|
|
25
|
+
severity: pattern.severity,
|
|
26
|
+
category: pattern.category || 'prompt-injection',
|
|
27
|
+
title: pattern.name,
|
|
28
|
+
file: 'SKILL.md',
|
|
29
|
+
line: lineNumber,
|
|
30
|
+
detail: pattern.description || `Pattern match: ${pattern.name}`,
|
|
31
|
+
evidence: matches.length > 1 ? `${matches.length} matches found` : `Match: "${truncate(matches[0], 100)}"`,
|
|
32
|
+
patternId: pattern.id
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Additional heuristic checks
|
|
37
|
+
// Check for excessively long markdown (could hide malicious content)
|
|
38
|
+
if (markdown.length > 50000) {
|
|
39
|
+
findings.push({
|
|
40
|
+
severity: 'LOW',
|
|
41
|
+
category: 'suspicious-size',
|
|
42
|
+
title: 'Unusually large skill documentation',
|
|
43
|
+
file: 'SKILL.md',
|
|
44
|
+
detail: `Skill documentation is ${markdown.length} characters`,
|
|
45
|
+
evidence: 'Large files can hide malicious content'
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
// Check for base64-looking strings in markdown (potential obfuscation)
|
|
49
|
+
const base64Pattern = /[A-Za-z0-9+\/]{50,}={0,2}/g;
|
|
50
|
+
const base64Matches = markdown.match(base64Pattern);
|
|
51
|
+
if (base64Matches && base64Matches.length > 0) {
|
|
52
|
+
findings.push({
|
|
53
|
+
severity: 'MEDIUM',
|
|
54
|
+
category: 'obfuscation',
|
|
55
|
+
title: 'Possible base64-encoded content in markdown',
|
|
56
|
+
file: 'SKILL.md',
|
|
57
|
+
detail: `Found ${base64Matches.length} base64-looking string(s)`,
|
|
58
|
+
evidence: 'Base64 encoding can hide malicious instructions'
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
layer: 'markdown',
|
|
63
|
+
findings
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Find line number for a match in text
|
|
68
|
+
*/
|
|
69
|
+
function findLineNumber(text, match) {
|
|
70
|
+
const index = text.indexOf(match);
|
|
71
|
+
if (index === -1)
|
|
72
|
+
return undefined;
|
|
73
|
+
const beforeMatch = text.substring(0, index);
|
|
74
|
+
const lineNumber = beforeMatch.split('\n').length;
|
|
75
|
+
return lineNumber;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Truncate string for display
|
|
79
|
+
*/
|
|
80
|
+
function truncate(str, maxLength) {
|
|
81
|
+
// Remove newlines and excessive whitespace
|
|
82
|
+
const cleaned = str.replace(/\s+/g, ' ').trim();
|
|
83
|
+
if (cleaned.length <= maxLength) {
|
|
84
|
+
return cleaned;
|
|
85
|
+
}
|
|
86
|
+
return cleaned.substring(0, maxLength) + '...';
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=injection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injection.js","sourceRoot":"","sources":["../../src/layers/injection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 1: Permission Audit
|
|
3
|
+
* Analyzes YAML frontmatter to identify requested permissions and assess risk
|
|
4
|
+
*/
|
|
5
|
+
import type { Skill, LayerResult } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Scan skill permissions from YAML frontmatter
|
|
8
|
+
*/
|
|
9
|
+
export declare function scanPermissions(skill: Skill): Promise<LayerResult>;
|
|
10
|
+
//# sourceMappingURL=permissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/layers/permissions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAW,WAAW,EAAW,MAAM,aAAa,CAAC;AAGxE;;GAEG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC,CAiIxE"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 1: Permission Audit
|
|
3
|
+
* Analyzes YAML frontmatter to identify requested permissions and assess risk
|
|
4
|
+
*/
|
|
5
|
+
import { loadPatterns } from '../pattern-loader.js';
|
|
6
|
+
/**
|
|
7
|
+
* Scan skill permissions from YAML frontmatter
|
|
8
|
+
*/
|
|
9
|
+
export async function scanPermissions(skill) {
|
|
10
|
+
const findings = [];
|
|
11
|
+
const metadata = skill.metadata;
|
|
12
|
+
// Load credential patterns for environment variable scanning
|
|
13
|
+
const credentialPatterns = await loadPatterns('credential-patterns');
|
|
14
|
+
// Check for no declared permissions (suspicious)
|
|
15
|
+
if (!metadata.bins && !metadata.env && !metadata['allowed-tools']) {
|
|
16
|
+
findings.push({
|
|
17
|
+
severity: 'LOW',
|
|
18
|
+
category: 'permissions',
|
|
19
|
+
title: 'No declared permissions',
|
|
20
|
+
file: 'SKILL.md',
|
|
21
|
+
detail: 'Skill declares no permissions (bins, env, or allowed-tools)',
|
|
22
|
+
evidence: 'Legitimate skills typically declare at least one permission'
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
// Scan environment variables for credential patterns
|
|
26
|
+
if (metadata.env && Array.isArray(metadata.env)) {
|
|
27
|
+
for (const envVar of metadata.env) {
|
|
28
|
+
for (const pattern of credentialPatterns) {
|
|
29
|
+
if (pattern.layer !== 'permissions')
|
|
30
|
+
continue;
|
|
31
|
+
const regex = new RegExp(pattern.match.value, pattern.match.flags);
|
|
32
|
+
if (regex.test(envVar)) {
|
|
33
|
+
findings.push({
|
|
34
|
+
severity: pattern.severity,
|
|
35
|
+
category: 'credential-request',
|
|
36
|
+
title: pattern.name,
|
|
37
|
+
file: 'SKILL.md',
|
|
38
|
+
detail: `Requests credential environment variable: ${envVar}`,
|
|
39
|
+
evidence: pattern.description,
|
|
40
|
+
patternId: pattern.id
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Check allowed-tools for dangerous permissions
|
|
47
|
+
if (metadata['allowed-tools'] && Array.isArray(metadata['allowed-tools'])) {
|
|
48
|
+
const tools = metadata['allowed-tools'];
|
|
49
|
+
// Check for shell/command execution
|
|
50
|
+
const shellTools = ['shell', 'bash', 'exec', 'command'];
|
|
51
|
+
const hasShell = tools.some(tool => shellTools.some(shellTool => tool.toLowerCase().includes(shellTool)));
|
|
52
|
+
if (hasShell) {
|
|
53
|
+
findings.push({
|
|
54
|
+
severity: 'CRITICAL',
|
|
55
|
+
category: 'dangerous-permission',
|
|
56
|
+
title: 'Shell execution permission',
|
|
57
|
+
file: 'SKILL.md',
|
|
58
|
+
detail: 'Skill requests shell/command execution capability',
|
|
59
|
+
evidence: `Allowed tools: ${tools.filter(t => shellTools.some(st => t.toLowerCase().includes(st))).join(', ')}`
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
// Check for network access
|
|
63
|
+
const networkTools = ['browser', 'http', 'fetch', 'network', 'web', 'curl', 'wget'];
|
|
64
|
+
const hasNetwork = tools.some(tool => networkTools.some(netTool => tool.toLowerCase().includes(netTool)));
|
|
65
|
+
if (hasNetwork) {
|
|
66
|
+
findings.push({
|
|
67
|
+
severity: 'HIGH',
|
|
68
|
+
category: 'network-permission',
|
|
69
|
+
title: 'Network access permission',
|
|
70
|
+
file: 'SKILL.md',
|
|
71
|
+
detail: 'Skill requests network/HTTP access capability',
|
|
72
|
+
evidence: `Allowed tools: ${tools.filter(t => networkTools.some(nt => t.toLowerCase().includes(nt))).join(', ')}`
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
// Check for file system access
|
|
76
|
+
const fsTools = ['file', 'filesystem', 'fs', 'read', 'write'];
|
|
77
|
+
const hasFileSystem = tools.some(tool => fsTools.some(fsTool => tool.toLowerCase().includes(fsTool)));
|
|
78
|
+
if (hasFileSystem) {
|
|
79
|
+
findings.push({
|
|
80
|
+
severity: 'MEDIUM',
|
|
81
|
+
category: 'filesystem-permission',
|
|
82
|
+
title: 'File system access permission',
|
|
83
|
+
file: 'SKILL.md',
|
|
84
|
+
detail: 'Skill requests file system access capability',
|
|
85
|
+
evidence: `Allowed tools: ${tools.filter(t => fsTools.some(ft => t.toLowerCase().includes(ft))).join(', ')}`
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Check for dangerous system binaries
|
|
90
|
+
if (metadata.bins && Array.isArray(metadata.bins)) {
|
|
91
|
+
const dangerousBins = [
|
|
92
|
+
{ pattern: /^(bash|sh|zsh|fish|cmd|powershell)$/i, severity: 'CRITICAL', reason: 'Shell interpreter' },
|
|
93
|
+
{ pattern: /^(curl|wget|fetch)$/i, severity: 'HIGH', reason: 'Network download tool' },
|
|
94
|
+
{ pattern: /^(nc|netcat|ncat)$/i, severity: 'CRITICAL', reason: 'Network connection tool' },
|
|
95
|
+
{ pattern: /^(python|node|ruby|perl|php)$/i, severity: 'HIGH', reason: 'Script interpreter' },
|
|
96
|
+
{ pattern: /^(docker|kubectl|podman)$/i, severity: 'HIGH', reason: 'Container management' },
|
|
97
|
+
{ pattern: /^(ssh|scp|sftp)$/i, severity: 'HIGH', reason: 'Remote access tool' },
|
|
98
|
+
{ pattern: /^(git)$/i, severity: 'MEDIUM', reason: 'Version control (can clone arbitrary repos)' }
|
|
99
|
+
];
|
|
100
|
+
for (const bin of metadata.bins) {
|
|
101
|
+
for (const dangerous of dangerousBins) {
|
|
102
|
+
if (dangerous.pattern.test(bin)) {
|
|
103
|
+
findings.push({
|
|
104
|
+
severity: dangerous.severity,
|
|
105
|
+
category: 'dangerous-binary',
|
|
106
|
+
title: `Dangerous binary: ${bin}`,
|
|
107
|
+
file: 'SKILL.md',
|
|
108
|
+
detail: `Requests access to system binary: ${bin}`,
|
|
109
|
+
evidence: dangerous.reason
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
layer: 'permissions',
|
|
117
|
+
findings
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/layers/permissions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern loader utility
|
|
3
|
+
* Loads detection patterns from JSON files
|
|
4
|
+
*/
|
|
5
|
+
import type { Pattern } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Load patterns from a specific category file
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadPatterns(category: string): Promise<Pattern[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Load all available patterns
|
|
12
|
+
*/
|
|
13
|
+
export declare function loadAllPatterns(): Promise<Pattern[]>;
|
|
14
|
+
//# sourceMappingURL=pattern-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-loader.d.ts","sourceRoot":"","sources":["../src/pattern-loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAmB,MAAM,YAAY,CAAC;AAO3D;;GAEG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAiBvE;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAkB1D"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern loader utility
|
|
3
|
+
* Loads detection patterns from JSON files
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync } from 'fs';
|
|
6
|
+
import { join, dirname } from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
10
|
+
const patternCache = new Map();
|
|
11
|
+
/**
|
|
12
|
+
* Load patterns from a specific category file
|
|
13
|
+
*/
|
|
14
|
+
export async function loadPatterns(category) {
|
|
15
|
+
// Check cache first
|
|
16
|
+
if (patternCache.has(category)) {
|
|
17
|
+
return patternCache.get(category);
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const patternPath = join(__dirname, 'patterns', `${category}.json`);
|
|
21
|
+
const content = readFileSync(patternPath, 'utf-8');
|
|
22
|
+
const data = JSON.parse(content);
|
|
23
|
+
patternCache.set(category, data.patterns);
|
|
24
|
+
return data.patterns;
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
console.warn(`Warning: Could not load patterns for category: ${category}`);
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Load all available patterns
|
|
33
|
+
*/
|
|
34
|
+
export async function loadAllPatterns() {
|
|
35
|
+
const categories = [
|
|
36
|
+
'prompt-injection',
|
|
37
|
+
'dangerous-imports',
|
|
38
|
+
'sensitive-paths',
|
|
39
|
+
'exfiltration-sinks',
|
|
40
|
+
'obfuscation',
|
|
41
|
+
'credential-patterns'
|
|
42
|
+
];
|
|
43
|
+
const allPatterns = [];
|
|
44
|
+
for (const category of categories) {
|
|
45
|
+
const patterns = await loadPatterns(category);
|
|
46
|
+
allPatterns.push(...patterns);
|
|
47
|
+
}
|
|
48
|
+
return allPatterns;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=pattern-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-loader.js","sourceRoot":"","sources":["../src/pattern-loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAGpC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,MAAM,YAAY,GAAG,IAAI,GAAG,EAAqB,CAAC;AAElD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,oBAAoB;IACpB,IAAI,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,OAAO,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC;IACrC,CAAC;IAED,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,GAAG,QAAQ,OAAO,CAAC,CAAC;QACpE,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,IAAI,GAAoB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAElD,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,kDAAkD,QAAQ,EAAE,CAAC,CAAC;QAC3E,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,UAAU,GAAG;QACjB,kBAAkB;QAClB,mBAAmB;QACnB,iBAAiB;QACjB,oBAAoB;QACpB,aAAa;QACb,qBAAqB;KACtB,CAAC;IAEF,MAAM,WAAW,GAAc,EAAE,CAAC;IAElC,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC9C,WAAW,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"category": "credential-patterns",
|
|
3
|
+
"patterns": [
|
|
4
|
+
{
|
|
5
|
+
"id": "cp-001",
|
|
6
|
+
"name": "env-var-api-key",
|
|
7
|
+
"description": "Requests API key environment variable",
|
|
8
|
+
"severity": "HIGH",
|
|
9
|
+
"match": {
|
|
10
|
+
"type": "regex",
|
|
11
|
+
"value": "(API_KEY|APIKEY|API_SECRET)",
|
|
12
|
+
"flags": "g"
|
|
13
|
+
},
|
|
14
|
+
"layer": "permissions"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"id": "cp-002",
|
|
18
|
+
"name": "env-var-token",
|
|
19
|
+
"description": "Requests token environment variable",
|
|
20
|
+
"severity": "HIGH",
|
|
21
|
+
"match": {
|
|
22
|
+
"type": "regex",
|
|
23
|
+
"value": "(TOKEN|ACCESS_TOKEN|AUTH_TOKEN|BEARER_TOKEN)",
|
|
24
|
+
"flags": "g"
|
|
25
|
+
},
|
|
26
|
+
"layer": "permissions"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "cp-003",
|
|
30
|
+
"name": "env-var-password",
|
|
31
|
+
"description": "Requests password environment variable",
|
|
32
|
+
"severity": "HIGH",
|
|
33
|
+
"match": {
|
|
34
|
+
"type": "regex",
|
|
35
|
+
"value": "(PASSWORD|PASSWD|PWD)(?!_HASH)",
|
|
36
|
+
"flags": "g"
|
|
37
|
+
},
|
|
38
|
+
"layer": "permissions"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "cp-004",
|
|
42
|
+
"name": "env-var-secret",
|
|
43
|
+
"description": "Requests secret environment variable",
|
|
44
|
+
"severity": "HIGH",
|
|
45
|
+
"match": {
|
|
46
|
+
"type": "regex",
|
|
47
|
+
"value": "(SECRET|CLIENT_SECRET)",
|
|
48
|
+
"flags": "g"
|
|
49
|
+
},
|
|
50
|
+
"layer": "permissions"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"id": "cp-005",
|
|
54
|
+
"name": "env-var-credential",
|
|
55
|
+
"description": "Requests credential environment variable",
|
|
56
|
+
"severity": "HIGH",
|
|
57
|
+
"match": {
|
|
58
|
+
"type": "regex",
|
|
59
|
+
"value": "(CREDENTIAL|CREDENTIALS)",
|
|
60
|
+
"flags": "g"
|
|
61
|
+
},
|
|
62
|
+
"layer": "permissions"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"id": "cp-006",
|
|
66
|
+
"name": "process-env-access",
|
|
67
|
+
"description": "Accesses process.env in code",
|
|
68
|
+
"severity": "MEDIUM",
|
|
69
|
+
"match": {
|
|
70
|
+
"type": "regex",
|
|
71
|
+
"value": "process\\.env\\.[A-Z_]+",
|
|
72
|
+
"flags": "g"
|
|
73
|
+
},
|
|
74
|
+
"layer": "code"
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|