acidtest 0.5.2 → 0.7.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.
Files changed (58) hide show
  1. package/.github/workflows/acidtest-example.yml +4 -4
  2. package/.github/workflows/acidtest-template.yml +1 -1
  3. package/README.md +70 -5
  4. package/dist/config.d.ts +19 -0
  5. package/dist/config.d.ts.map +1 -0
  6. package/dist/config.js +69 -0
  7. package/dist/config.js.map +1 -0
  8. package/dist/config.test.d.ts +5 -0
  9. package/dist/config.test.d.ts.map +1 -0
  10. package/dist/config.test.js +69 -0
  11. package/dist/config.test.js.map +1 -0
  12. package/dist/index.js +45 -8
  13. package/dist/index.js.map +1 -1
  14. package/dist/layers/code.js +116 -6
  15. package/dist/layers/code.js.map +1 -1
  16. package/dist/layers/code.test.d.ts +5 -0
  17. package/dist/layers/code.test.d.ts.map +1 -0
  18. package/dist/layers/code.test.js +214 -0
  19. package/dist/layers/code.test.js.map +1 -0
  20. package/dist/layers/injection.d.ts.map +1 -1
  21. package/dist/layers/injection.js +2 -1
  22. package/dist/layers/injection.js.map +1 -1
  23. package/dist/layers/permissions.d.ts.map +1 -1
  24. package/dist/layers/permissions.js +2 -1
  25. package/dist/layers/permissions.js.map +1 -1
  26. package/dist/patterns/credential-patterns.json +10 -1
  27. package/dist/patterns/dangerous-imports.json +40 -4
  28. package/dist/remediation.test.d.ts +5 -0
  29. package/dist/remediation.test.d.ts.map +1 -0
  30. package/dist/remediation.test.js +74 -0
  31. package/dist/remediation.test.js.map +1 -0
  32. package/dist/reporter.d.ts +4 -1
  33. package/dist/reporter.d.ts.map +1 -1
  34. package/dist/reporter.js +83 -3
  35. package/dist/reporter.js.map +1 -1
  36. package/dist/scanner.d.ts +1 -1
  37. package/dist/scanner.d.ts.map +1 -1
  38. package/dist/scanner.js +31 -3
  39. package/dist/scanner.js.map +1 -1
  40. package/dist/scanner.test.d.ts +5 -0
  41. package/dist/scanner.test.d.ts.map +1 -0
  42. package/dist/scanner.test.js +77 -0
  43. package/dist/scanner.test.js.map +1 -0
  44. package/dist/scoring.test.d.ts +5 -0
  45. package/dist/scoring.test.d.ts.map +1 -0
  46. package/dist/scoring.test.js +301 -0
  47. package/dist/scoring.test.js.map +1 -0
  48. package/dist/types.d.ts +34 -0
  49. package/dist/types.d.ts.map +1 -1
  50. package/dist/watch.d.ts +14 -0
  51. package/dist/watch.d.ts.map +1 -0
  52. package/dist/watch.js +135 -0
  53. package/dist/watch.js.map +1 -0
  54. package/dist/watch.test.d.ts +5 -0
  55. package/dist/watch.test.d.ts.map +1 -0
  56. package/dist/watch.test.js +53 -0
  57. package/dist/watch.test.js.map +1 -0
  58. package/package.json +13 -4
@@ -27,7 +27,7 @@ jobs:
27
27
  if: hashFiles('src/scanner.ts') != ''
28
28
  uses: actions/setup-node@v4
29
29
  with:
30
- node-version: '18'
30
+ node-version: '20'
31
31
 
32
32
  - name: Run AcidTest
33
33
  run: |
@@ -51,7 +51,7 @@ jobs:
51
51
  if: hashFiles('src/scanner.ts') != ''
52
52
  uses: actions/setup-node@v4
53
53
  with:
54
- node-version: '18'
54
+ node-version: '20'
55
55
 
56
56
  - name: Run AcidTest
57
57
  id: acidtest
@@ -112,7 +112,7 @@ jobs:
112
112
  if: hashFiles('src/scanner.ts') != ''
113
113
  uses: actions/setup-node@v4
114
114
  with:
115
- node-version: '18'
115
+ node-version: '20'
116
116
 
117
117
  - name: Run AcidTest on all skills
118
118
  run: |
@@ -163,7 +163,7 @@ jobs:
163
163
  if: hashFiles('src/scanner.ts') != ''
164
164
  uses: actions/setup-node@v4
165
165
  with:
166
- node-version: '18'
166
+ node-version: '20'
167
167
 
168
168
  - name: Run AcidTest
169
169
  id: scan
@@ -22,7 +22,7 @@ jobs:
22
22
  if: hashFiles('src/scanner.ts') != ''
23
23
  uses: actions/setup-node@v4
24
24
  with:
25
- node-version: '18'
25
+ node-version: '20'
26
26
 
27
27
  - name: Run AcidTest
28
28
  run: |
package/README.md CHANGED
@@ -4,11 +4,21 @@ Security scanner for AI agent skills and MCP servers. Scan before you install.
4
4
 
5
5
  ## The Problem
6
6
 
7
- The AI agent ecosystem is growing rapidly with thousands of skills and MCP servers. Security concerns include:
8
- - **AgentSkills**: 66,000+ skills with 26% containing vulnerabilities
9
- - **230+** confirmed malicious skills uploaded to ClawHub in one week
10
- - **341** skills flagged in the ClawHavoc campaign
11
- - **MCP Servers**: New ecosystem with similar security risks
7
+ The AI agent ecosystem is growing rapidly, but security lags behind adoption:
8
+
9
+ - **No centralized vetting**: Unlike mobile app stores, there's no security review before skills are published
10
+ - **Broad permissions**: Skills can request file system access, environment variables, and network calls
11
+ - **Supply chain risks**: Dependencies and third-party code run with full skill permissions
12
+ - **Prompt injection**: Malicious skills can manipulate AI behavior through carefully crafted prompts
13
+ - **Credential harvesting**: Skills requesting API keys and tokens without proper justification
14
+
15
+ Recent ecosystem incidents highlight these risks:
16
+ - Mass uploads of malicious skills to public marketplaces
17
+ - Skills with undeclared network calls exfiltrating data
18
+ - Obfuscated code hiding malicious behavior
19
+ - Permission escalation through dynamic imports
20
+
21
+ **AcidTest provides security scanning before installation**, helping you identify risks before they reach your system.
12
22
 
13
23
  ## Quick Start
14
24
  ```bash
@@ -114,6 +124,16 @@ acidtest scan ./server/mcp.json # Direct manifest path
114
124
  # Scan all skills/servers in a directory
115
125
  acidtest scan-all ./directory
116
126
 
127
+ # Watch mode - re-scan on file changes
128
+ acidtest scan ./my-skill --watch
129
+ acidtest scan ./my-skill -w # Short form
130
+
131
+ # Show remediation suggestions
132
+ acidtest scan ./my-skill --fix
133
+
134
+ # Combine flags
135
+ acidtest scan ./my-skill --watch --fix
136
+
117
137
  # JSON output for programmatic use
118
138
  acidtest scan ./my-skill --json
119
139
 
@@ -121,6 +141,51 @@ acidtest scan ./my-skill --json
121
141
  acidtest serve
122
142
  ```
123
143
 
144
+ ### CLI Options
145
+
146
+ - `--watch`, `-w` - Watch for file changes and automatically re-scan
147
+ - Keyboard controls: `q` to quit, `r` to force re-scan, `c` to clear terminal
148
+ - Use `--no-clear` to preserve terminal history between scans
149
+ - `--fix` - Show actionable remediation suggestions for each finding
150
+ - `--json` - Output results as JSON for programmatic use
151
+ - `--no-clear` - Don't clear terminal between scans (watch mode only)
152
+
153
+ ### Configuration File
154
+
155
+ Create a `.acidtest.json` file in your skill directory to customize scanning behavior:
156
+
157
+ ```json
158
+ {
159
+ "ignore": {
160
+ "patterns": ["di-008"],
161
+ "categories": ["obfuscation"],
162
+ "files": ["vendor/**", "*.min.js"]
163
+ },
164
+ "thresholds": {
165
+ "minScore": 80,
166
+ "failOn": ["CRITICAL", "HIGH"]
167
+ },
168
+ "output": {
169
+ "format": "detailed",
170
+ "showRemediation": true,
171
+ "colors": true
172
+ }
173
+ }
174
+ ```
175
+
176
+ **Configuration Options:**
177
+
178
+ - `ignore.patterns` - Array of pattern IDs to suppress (e.g., `["di-001", "cp-006"]`)
179
+ - `ignore.categories` - Array of categories to suppress (e.g., `["obfuscation"]`)
180
+ - `ignore.files` - Array of glob patterns for files to skip scanning
181
+ - `thresholds.minScore` - Minimum passing score (0-100). Exit with error if score is below this
182
+ - `thresholds.failOn` - Array of severities that cause scan to fail (e.g., `["CRITICAL", "HIGH"]`)
183
+ - `output.format` - Output format: `"detailed"`, `"compact"`, or `"json"`
184
+ - `output.showRemediation` - Show remediation suggestions (boolean)
185
+ - `output.colors` - Enable/disable colored output (boolean)
186
+
187
+ CLI flags override config file settings.
188
+
124
189
  ### Use as MCP Server
125
190
 
126
191
  AcidTest can run as an MCP (Model Context Protocol) server, allowing AI agents like Claude to scan skills and MCP servers before installation.
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Configuration file loader
3
+ * Loads and validates .acidtest.json config files
4
+ */
5
+ import type { AcidTestConfig } from './types.js';
6
+ /**
7
+ * Load AcidTest configuration from directory
8
+ * Looks for .acidtest.json in the skill directory
9
+ */
10
+ export declare function loadConfig(directory: string): AcidTestConfig;
11
+ /**
12
+ * Get default configuration
13
+ */
14
+ export declare function getDefaultConfig(): AcidTestConfig;
15
+ /**
16
+ * Merge user config with defaults
17
+ */
18
+ export declare function mergeConfig(userConfig: AcidTestConfig): AcidTestConfig;
19
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAe5D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,CAiBjD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,cAAc,GAAG,cAAc,CAmBtE"}
package/dist/config.js ADDED
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Configuration file loader
3
+ * Loads and validates .acidtest.json config files
4
+ */
5
+ import { readFileSync, existsSync } from 'fs';
6
+ import { join } from 'path';
7
+ /**
8
+ * Load AcidTest configuration from directory
9
+ * Looks for .acidtest.json in the skill directory
10
+ */
11
+ export function loadConfig(directory) {
12
+ const configPath = join(directory, '.acidtest.json');
13
+ if (!existsSync(configPath)) {
14
+ return {}; // No config, use defaults
15
+ }
16
+ try {
17
+ const content = readFileSync(configPath, 'utf-8');
18
+ const config = JSON.parse(content);
19
+ return config;
20
+ }
21
+ catch (error) {
22
+ console.warn(`Warning: Invalid .acidtest.json: ${error.message}`);
23
+ return {};
24
+ }
25
+ }
26
+ /**
27
+ * Get default configuration
28
+ */
29
+ export function getDefaultConfig() {
30
+ return {
31
+ ignore: {
32
+ patterns: [],
33
+ categories: [],
34
+ files: []
35
+ },
36
+ thresholds: {
37
+ minScore: 0,
38
+ failOn: []
39
+ },
40
+ output: {
41
+ format: 'detailed',
42
+ showRemediation: false,
43
+ colors: true
44
+ }
45
+ };
46
+ }
47
+ /**
48
+ * Merge user config with defaults
49
+ */
50
+ export function mergeConfig(userConfig) {
51
+ const defaults = getDefaultConfig();
52
+ return {
53
+ ignore: {
54
+ patterns: userConfig.ignore?.patterns ?? defaults.ignore.patterns,
55
+ categories: userConfig.ignore?.categories ?? defaults.ignore.categories,
56
+ files: userConfig.ignore?.files ?? defaults.ignore.files
57
+ },
58
+ thresholds: {
59
+ minScore: userConfig.thresholds?.minScore ?? defaults.thresholds.minScore,
60
+ failOn: userConfig.thresholds?.failOn ?? defaults.thresholds.failOn
61
+ },
62
+ output: {
63
+ format: userConfig.output?.format ?? defaults.output.format,
64
+ showRemediation: userConfig.output?.showRemediation ?? defaults.output.showRemediation,
65
+ colors: userConfig.output?.colors ?? defaults.output.colors
66
+ }
67
+ };
68
+ }
69
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAErD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC,CAAC,0BAA0B;IACvC,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAmB,CAAC;QACrD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,oCAAqC,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7E,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO;QACL,MAAM,EAAE;YACN,QAAQ,EAAE,EAAE;YACZ,UAAU,EAAE,EAAE;YACd,KAAK,EAAE,EAAE;SACV;QACD,UAAU,EAAE;YACV,QAAQ,EAAE,CAAC;YACX,MAAM,EAAE,EAAE;SACX;QACD,MAAM,EAAE;YACN,MAAM,EAAE,UAAU;YAClB,eAAe,EAAE,KAAK;YACtB,MAAM,EAAE,IAAI;SACb;KACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,UAA0B;IACpD,MAAM,QAAQ,GAAG,gBAAgB,EAAE,CAAC;IAEpC,OAAO;QACL,MAAM,EAAE;YACN,QAAQ,EAAE,UAAU,CAAC,MAAM,EAAE,QAAQ,IAAI,QAAQ,CAAC,MAAO,CAAC,QAAQ;YAClE,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,UAAU,IAAI,QAAQ,CAAC,MAAO,CAAC,UAAU;YACxE,KAAK,EAAE,UAAU,CAAC,MAAM,EAAE,KAAK,IAAI,QAAQ,CAAC,MAAO,CAAC,KAAK;SAC1D;QACD,UAAU,EAAE;YACV,QAAQ,EAAE,UAAU,CAAC,UAAU,EAAE,QAAQ,IAAI,QAAQ,CAAC,UAAW,CAAC,QAAQ;YAC1E,MAAM,EAAE,UAAU,CAAC,UAAU,EAAE,MAAM,IAAI,QAAQ,CAAC,UAAW,CAAC,MAAM;SACrE;QACD,MAAM,EAAE;YACN,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,MAAM,IAAI,QAAQ,CAAC,MAAO,CAAC,MAAM;YAC5D,eAAe,EAAE,UAAU,CAAC,MAAM,EAAE,eAAe,IAAI,QAAQ,CAAC,MAAO,CAAC,eAAe;YACvF,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,MAAM,IAAI,QAAQ,CAAC,MAAO,CAAC,MAAM;SAC7D;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for config loading
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.d.ts","sourceRoot":"","sources":["../src/config.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Tests for config loading
3
+ */
4
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
5
+ import { mkdirSync, writeFileSync, rmSync } from 'fs';
6
+ import { join } from 'path';
7
+ import { loadConfig, mergeConfig, getDefaultConfig } from './config.js';
8
+ describe('Config Loading', () => {
9
+ const testDir = join(process.cwd(), 'test-config-temp');
10
+ beforeEach(() => {
11
+ mkdirSync(testDir, { recursive: true });
12
+ });
13
+ afterEach(() => {
14
+ rmSync(testDir, { recursive: true, force: true });
15
+ });
16
+ it('should return empty config when .acidtest.json does not exist', () => {
17
+ const config = loadConfig(testDir);
18
+ expect(config).toEqual({});
19
+ });
20
+ it('should load valid .acidtest.json config', () => {
21
+ const configData = {
22
+ ignore: {
23
+ patterns: ['di-001', 'di-002'],
24
+ categories: ['obfuscation']
25
+ },
26
+ thresholds: {
27
+ minScore: 80,
28
+ failOn: ['CRITICAL', 'HIGH']
29
+ }
30
+ };
31
+ writeFileSync(join(testDir, '.acidtest.json'), JSON.stringify(configData, null, 2));
32
+ const config = loadConfig(testDir);
33
+ expect(config).toEqual(configData);
34
+ });
35
+ it('should return empty config on invalid JSON', () => {
36
+ writeFileSync(join(testDir, '.acidtest.json'), 'invalid json {');
37
+ const config = loadConfig(testDir);
38
+ expect(config).toEqual({});
39
+ });
40
+ it('should merge user config with defaults', () => {
41
+ const userConfig = {
42
+ ignore: {
43
+ patterns: ['di-001']
44
+ },
45
+ thresholds: {
46
+ minScore: 90
47
+ }
48
+ };
49
+ const merged = mergeConfig(userConfig);
50
+ const defaults = getDefaultConfig();
51
+ expect(merged.ignore?.patterns).toEqual(['di-001']);
52
+ expect(merged.ignore?.categories).toEqual(defaults.ignore.categories);
53
+ expect(merged.thresholds?.minScore).toBe(90);
54
+ expect(merged.thresholds?.failOn).toEqual(defaults.thresholds.failOn);
55
+ expect(merged.output?.format).toBe(defaults.output.format);
56
+ });
57
+ it('should handle partial config', () => {
58
+ const userConfig = {
59
+ thresholds: {
60
+ failOn: ['CRITICAL']
61
+ }
62
+ };
63
+ const merged = mergeConfig(userConfig);
64
+ const defaults = getDefaultConfig();
65
+ expect(merged.ignore?.patterns).toEqual(defaults.ignore.patterns);
66
+ expect(merged.thresholds?.failOn).toEqual(['CRITICAL']);
67
+ });
68
+ });
69
+ //# sourceMappingURL=config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.js","sourceRoot":"","sources":["../src/config.test.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -5,10 +5,11 @@
5
5
  */
6
6
  import { scanSkill, scanAllSkills } from "./scanner.js";
7
7
  import { reportToTerminal, reportAsJSON } from "./reporter.js";
8
+ import { loadConfig, mergeConfig } from "./config.js";
8
9
  import { join, dirname } from "path";
9
10
  import { fileURLToPath } from "url";
10
11
  import { spawn } from "child_process";
11
- const VERSION = "0.5.2";
12
+ const VERSION = "0.7.0";
12
13
  /**
13
14
  * Main CLI function
14
15
  */
@@ -50,23 +51,50 @@ async function main() {
50
51
  async function handleScan(args) {
51
52
  // Parse flags
52
53
  const jsonOutput = args.includes("--json");
53
- const paths = args.filter((arg) => !arg.startsWith("--"));
54
+ const watchMode = args.includes("--watch") || args.includes("-w");
55
+ const noClear = args.includes("--no-clear");
56
+ const showFix = args.includes("--fix");
57
+ const paths = args.filter((arg) => !arg.startsWith("--") && arg !== "-w");
54
58
  if (paths.length === 0) {
55
59
  console.error("Error: No skill path provided");
56
- console.error("Usage: acidtest scan <path-to-skill> [--json]");
60
+ console.error("Usage: acidtest scan <path-to-skill> [--json] [--watch]");
57
61
  process.exit(1);
58
62
  }
59
63
  const skillPath = paths[0];
64
+ // Handle watch mode
65
+ if (watchMode) {
66
+ const { watchMode: startWatchMode } = await import('./watch.js');
67
+ await startWatchMode(skillPath, { noClear, jsonOutput, showRemediation: showFix });
68
+ return; // Watch mode handles its own exit
69
+ }
60
70
  try {
61
- const result = await scanSkill(skillPath);
71
+ // Load config from skill directory
72
+ const userConfig = loadConfig(skillPath);
73
+ const config = mergeConfig(userConfig);
74
+ // Show progress spinner for CLI scans (not for JSON output)
75
+ const result = await scanSkill(skillPath, !jsonOutput);
62
76
  if (jsonOutput) {
63
77
  reportAsJSON(result);
64
78
  }
65
79
  else {
66
- reportToTerminal(result);
80
+ // CLI flags override config
81
+ const showRemediation = showFix || (config.output?.showRemediation ?? false);
82
+ reportToTerminal(result, { showRemediation });
83
+ }
84
+ // Apply threshold checks from config
85
+ let shouldFail = result.status === "FAIL" || result.status === "DANGER";
86
+ // Check minScore threshold
87
+ if (config.thresholds?.minScore && result.score < config.thresholds.minScore) {
88
+ shouldFail = true;
67
89
  }
68
- // Exit with non-zero code for FAIL or DANGER
69
- if (result.status === "FAIL" || result.status === "DANGER") {
90
+ // Check failOn severity threshold
91
+ if (config.thresholds?.failOn && config.thresholds.failOn.length > 0) {
92
+ const hasFailSeverity = result.findings.some(f => config.thresholds.failOn.includes(f.severity));
93
+ if (hasFailSeverity) {
94
+ shouldFail = true;
95
+ }
96
+ }
97
+ if (shouldFail) {
70
98
  process.exit(1);
71
99
  }
72
100
  }
@@ -259,7 +287,7 @@ AcidTest v${VERSION}
259
287
  Security scanner for AI agent skills and MCP servers
260
288
 
261
289
  USAGE:
262
- acidtest scan <path> [--json]
290
+ acidtest scan <path> [--json] [--watch] [--fix] [--no-clear]
263
291
  acidtest scan-all <directory> [--json]
264
292
  acidtest demo
265
293
  acidtest serve
@@ -274,6 +302,9 @@ COMMANDS:
274
302
 
275
303
  OPTIONS:
276
304
  --json Output results as JSON
305
+ --watch, -w Watch for file changes and re-scan automatically
306
+ --fix Show actionable remediation suggestions for findings
307
+ --no-clear Don't clear terminal between scans (watch mode only)
277
308
  --version Print version number
278
309
  --help Show this help message
279
310
 
@@ -290,6 +321,12 @@ EXAMPLES:
290
321
  # Scan with JSON output
291
322
  acidtest scan ./my-skill --json
292
323
 
324
+ # Show remediation suggestions for findings
325
+ acidtest scan ./my-skill --fix
326
+
327
+ # Watch for changes and re-scan automatically
328
+ acidtest scan ./my-skill --watch
329
+
293
330
  # Scan all skills/servers in a directory
294
331
  acidtest scan-all ./directory
295
332
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -65,7 +65,8 @@ function scanCodeWithRegex(codeFile, patterns) {
65
65
  line: lineNumber,
66
66
  detail: pattern.description || `Pattern match: ${pattern.name}`,
67
67
  evidence: `Found ${matches.length} occurrence(s)`,
68
- patternId: pattern.id
68
+ patternId: pattern.id,
69
+ ...(pattern.remediation && { remediation: pattern.remediation })
69
70
  });
70
71
  }
71
72
  }
@@ -137,6 +138,9 @@ function detectSuspiciousPatterns(sourceFile, filePath) {
137
138
  const findings = [];
138
139
  const dynamicRequires = [];
139
140
  const evals = [];
141
+ const functionConstructors = [];
142
+ const propertyAccessBypasses = [];
143
+ const stringConcatenations = [];
140
144
  function visit(node) {
141
145
  // Check for eval() calls
142
146
  if (ts.isCallExpression(node)) {
@@ -145,14 +149,42 @@ function detectSuspiciousPatterns(sourceFile, filePath) {
145
149
  const lineNumber = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
146
150
  evals.push(lineNumber);
147
151
  }
148
- // Check for require() with non-literal arguments
152
+ // Check for require() with non-literal arguments (catches dynamic require, template literals, variables)
149
153
  if (ts.isIdentifier(expression) && expression.text === 'require') {
150
154
  if (node.arguments.length > 0) {
151
155
  const arg = node.arguments[0];
156
+ // Catches: require(variable), require(obj.prop), require(`template${expr}`)
152
157
  if (!ts.isStringLiteral(arg) && !ts.isNoSubstitutionTemplateLiteral(arg)) {
153
158
  const lineNumber = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
154
159
  dynamicRequires.push(lineNumber);
155
160
  }
161
+ // Check for string concatenation: require('child_' + 'process')
162
+ if (ts.isBinaryExpression(arg) && arg.operatorToken.kind === ts.SyntaxKind.PlusToken) {
163
+ const lineNumber = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
164
+ stringConcatenations.push(lineNumber);
165
+ }
166
+ }
167
+ }
168
+ }
169
+ // Check for Function constructor: new Function(...)
170
+ if (ts.isNewExpression(node)) {
171
+ const expression = node.expression;
172
+ if (ts.isIdentifier(expression) && expression.text === 'Function') {
173
+ const lineNumber = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
174
+ functionConstructors.push(lineNumber);
175
+ }
176
+ }
177
+ // Check for bracket notation property access on sensitive objects
178
+ // Catches: global['child_process'], process['env'], require['cache']
179
+ if (ts.isElementAccessExpression(node)) {
180
+ const expression = node.expression;
181
+ if (ts.isIdentifier(expression)) {
182
+ const objName = expression.text;
183
+ // Check if accessing sensitive global objects
184
+ const sensitiveObjects = ['global', 'process', 'require', 'module', 'exports'];
185
+ if (sensitiveObjects.includes(objName)) {
186
+ const lineNumber = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
187
+ propertyAccessBypasses.push(lineNumber);
156
188
  }
157
189
  }
158
190
  }
@@ -168,7 +200,8 @@ function detectSuspiciousPatterns(sourceFile, filePath) {
168
200
  file: filePath,
169
201
  line: dynamicRequires[0],
170
202
  detail: `Found ${dynamicRequires.length} dynamic require() call(s)`,
171
- evidence: 'Dynamic imports can load arbitrary modules'
203
+ evidence: 'Dynamic imports can load arbitrary modules',
204
+ patternId: 'ast-dynamic-require'
172
205
  });
173
206
  }
174
207
  // Add findings for eval usage
@@ -180,7 +213,47 @@ function detectSuspiciousPatterns(sourceFile, filePath) {
180
213
  file: filePath,
181
214
  line: evals[0],
182
215
  detail: `Found ${evals.length} eval() call(s)`,
183
- evidence: 'eval() can execute arbitrary code'
216
+ evidence: 'eval() can execute arbitrary code',
217
+ patternId: 'ast-eval'
218
+ });
219
+ }
220
+ // Add findings for Function constructor
221
+ if (functionConstructors.length > 0) {
222
+ findings.push({
223
+ severity: 'CRITICAL',
224
+ category: 'function-constructor',
225
+ title: 'Function constructor detected',
226
+ file: filePath,
227
+ line: functionConstructors[0],
228
+ detail: `Found ${functionConstructors.length} Function constructor call(s)`,
229
+ evidence: 'Function constructor can execute arbitrary code like eval()',
230
+ patternId: 'ast-function-constructor'
231
+ });
232
+ }
233
+ // Add findings for property access bypasses
234
+ if (propertyAccessBypasses.length > 0) {
235
+ findings.push({
236
+ severity: 'MEDIUM',
237
+ category: 'property-access-bypass',
238
+ title: 'Bracket notation on sensitive objects',
239
+ file: filePath,
240
+ line: propertyAccessBypasses[0],
241
+ detail: `Found ${propertyAccessBypasses.length} bracket notation access(es) on sensitive objects`,
242
+ evidence: 'Bracket notation can bypass static analysis: global["child_process"]',
243
+ patternId: 'ast-bracket-access'
244
+ });
245
+ }
246
+ // Add findings for string concatenation in require
247
+ if (stringConcatenations.length > 0) {
248
+ findings.push({
249
+ severity: 'HIGH',
250
+ category: 'string-concatenation',
251
+ title: 'String concatenation in require()',
252
+ file: filePath,
253
+ line: stringConcatenations[0],
254
+ detail: `Found ${stringConcatenations.length} concatenated string(s) in require()`,
255
+ evidence: 'String concatenation can hide malicious imports: require("child_" + "process")',
256
+ patternId: 'ast-string-concat'
184
257
  });
185
258
  }
186
259
  return findings;
@@ -206,6 +279,38 @@ function calculateEntropy(str) {
206
279
  }
207
280
  return entropy;
208
281
  }
282
+ /**
283
+ * Check if string matches common legitimate high-entropy patterns
284
+ */
285
+ function isLegitimateHighEntropyString(text) {
286
+ // JWT tokens (header.payload.signature format, starts with eyJ)
287
+ if (/^eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(text)) {
288
+ return true;
289
+ }
290
+ // UUID/GUID (8-4-4-4-12 format)
291
+ if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(text)) {
292
+ return true;
293
+ }
294
+ // Hex hashes (SHA256: 64 chars, SHA1: 40 chars, MD5: 32 chars)
295
+ if (/^[0-9a-f]{32}$|^[0-9a-f]{40}$|^[0-9a-f]{64}$/i.test(text)) {
296
+ return true;
297
+ }
298
+ // Base64 strings (common in configs, keys)
299
+ // Must have padding OR be very long (>100 chars suggests real encoded data)
300
+ // Short base64-looking strings without padding are suspicious
301
+ if (/^[A-Za-z0-9+/]+=+$/.test(text) && text.length % 4 === 0) {
302
+ return true; // Has proper padding
303
+ }
304
+ if (/^[A-Za-z0-9+/]+$/.test(text) && text.length > 100) {
305
+ return true; // Very long, likely real encoded data
306
+ }
307
+ // API keys with common prefixes (Stripe, GitHub, etc.)
308
+ if (/^(sk_|pk_|gh[ps]_|AKIA|ya29\.|glpat-|xox[abp]-)[A-Za-z0-9_-]+$/i.test(text)) {
309
+ // These ARE suspicious, so return false to flag them
310
+ return false;
311
+ }
312
+ return false;
313
+ }
209
314
  /**
210
315
  * Detect high-entropy strings that may indicate obfuscation
211
316
  */
@@ -218,16 +323,21 @@ function detectHighEntropyStrings(sourceFile, filePath) {
218
323
  // Check string literals and template literals
219
324
  if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
220
325
  const text = node.text;
221
- // Skip short strings and URLs (already detected elsewhere)
326
+ // Skip short strings
222
327
  if (text.length < MIN_LENGTH) {
223
328
  ts.forEachChild(node, visit);
224
329
  return;
225
330
  }
226
- // Skip URLs, they naturally have high entropy
331
+ // Skip URLs (already detected elsewhere)
227
332
  if (/^https?:\/\//.test(text)) {
228
333
  ts.forEachChild(node, visit);
229
334
  return;
230
335
  }
336
+ // Skip legitimate high-entropy strings (JWTs, UUIDs, hashes)
337
+ if (isLegitimateHighEntropyString(text)) {
338
+ ts.forEachChild(node, visit);
339
+ return;
340
+ }
231
341
  const entropy = calculateEntropy(text);
232
342
  if (entropy > ENTROPY_THRESHOLD) {
233
343
  const lineNumber = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;