agent-security-scanner-mcp 3.4.0 → 3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,6 +5,8 @@ Security scanner for AI coding agents and autonomous assistants. Scans code for
5
5
  [![npm downloads](https://img.shields.io/npm/dt/agent-security-scanner-mcp.svg)](https://www.npmjs.com/package/agent-security-scanner-mcp)
6
6
  [![npm version](https://img.shields.io/npm/v/agent-security-scanner-mcp.svg)](https://www.npmjs.com/package/agent-security-scanner-mcp)
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+ [![Benchmark: 97.7% precision](https://img.shields.io/badge/precision-97.7%25-brightgreen.svg)](benchmarks/RESULTS.md)
9
+ [![CI](https://github.com/sinewaveai/agent-security-scanner-mcp/actions/workflows/test.yml/badge.svg)](https://github.com/sinewaveai/agent-security-scanner-mcp/actions/workflows/test.yml)
8
10
 
9
11
  > **New in v3.3.0:** Full [OpenClaw](https://openclaw.ai) integration with 30+ rules targeting autonomous AI threats — data exfiltration, credential theft, messaging abuse, and unsafe automation. [See OpenClaw setup](#openclaw-integration).
10
12
 
@@ -917,4 +919,4 @@ npm install -g agent-security-scanner-mcp-full
917
919
 
918
920
  ## License
919
921
 
920
- MIT
922
+ MIT
package/analyzer.py CHANGED
@@ -11,7 +11,6 @@ import sys
11
11
  import json
12
12
  import os
13
13
  import re
14
- import argparse
15
14
  from typing import List, Dict, Any
16
15
 
17
16
  # Add the directory containing this script to the path
@@ -92,7 +91,6 @@ def analyze_file_regex(file_path):
92
91
  'column': match.start() + col_offset,
93
92
  'length': match.end() - match.start(),
94
93
  'severity': rule['severity'],
95
- 'confidence': rule.get('metadata', {}).get('confidence', 'MEDIUM'),
96
94
  'metadata': rule.get('metadata', {}),
97
95
  'engine': 'regex'
98
96
  })
@@ -193,7 +191,6 @@ def analyze_file_ast(file_path):
193
191
  'column': f.column,
194
192
  'length': length,
195
193
  'severity': f.severity,
196
- 'confidence': f.metadata.get('confidence', getattr(f, 'confidence', 'MEDIUM')),
197
194
  'metadata': f.metadata,
198
195
  'engine': 'taint' if is_taint else 'ast',
199
196
  })
@@ -232,30 +229,16 @@ def analyze_file(file_path):
232
229
 
233
230
 
234
231
  def main():
235
- parser = argparse.ArgumentParser(description='Security Analyzer - AST-based with regex fallback')
236
- parser.add_argument('file_path', help='Path to the file to analyze')
237
- parser.add_argument('--engine', choices=['auto', 'ast', 'regex'], default='auto',
238
- help='Analysis engine: auto (default), ast (tree-sitter only), regex (regex only)')
239
- args = parser.parse_args()
232
+ if len(sys.argv) < 2:
233
+ print(json.dumps({'error': 'No file path provided'}))
234
+ sys.exit(1)
240
235
 
241
- file_path = args.file_path
236
+ file_path = sys.argv[1]
242
237
  if not os.path.exists(file_path):
243
238
  print(json.dumps({'error': f'File not found: {file_path}'}))
244
239
  sys.exit(1)
245
240
 
246
- engine = args.engine
247
-
248
- if engine == 'regex':
249
- results = analyze_file_regex(file_path)
250
- elif engine == 'ast':
251
- if not HAS_AST_ENGINE:
252
- print(json.dumps({'error': 'AST engine requested but tree-sitter is not available. Install dependencies: python3 -m pip install -r requirements.txt'}))
253
- sys.exit(1)
254
- results = analyze_file_ast(file_path)
255
- else:
256
- # auto: use AST if available, otherwise regex
257
- results = analyze_file(file_path)
258
-
241
+ results = analyze_file(file_path)
259
242
  print(json.dumps(results))
260
243
 
261
244
 
package/index.js CHANGED
@@ -17,12 +17,9 @@ import { fixSecuritySchema, fixSecurity } from './src/tools/fix-security.js';
17
17
  import { loadPackageLists, checkPackageSchema, checkPackage, getPackageStats } from './src/tools/check-package.js';
18
18
  import { scanPackagesSchema, scanPackages } from './src/tools/scan-packages.js';
19
19
  import { scanAgentPromptSchema, scanAgentPrompt } from './src/tools/scan-prompt.js';
20
- import { scanDiffSchema, scanDiff } from './src/tools/scan-diff.js';
21
- import { scanProjectSchema, scanProject } from './src/tools/scan-project.js';
22
20
  import { runInit } from './src/cli/init.js';
23
21
  import { runDoctor } from './src/cli/doctor.js';
24
22
  import { runDemo } from './src/cli/demo.js';
25
- import { runInitHooks } from './src/cli/init-hooks.js';
26
23
 
27
24
  // Handle both ESM and CJS bundling (Smithery bundles to CJS)
28
25
  let __dirname;
@@ -137,22 +134,6 @@ server.tool(
137
134
  scanAgentPrompt
138
135
  );
139
136
 
140
- // Register scan_git_diff tool
141
- server.tool(
142
- "scan_git_diff",
143
- "Scan git diff for new security vulnerabilities. Only reports issues on changed lines. Use for PR reviews.",
144
- scanDiffSchema,
145
- scanDiff
146
- );
147
-
148
- // Register scan_project tool
149
- server.tool(
150
- "scan_project",
151
- "Scan an entire directory for security vulnerabilities with .gitignore support and security grading. Use verbosity='minimal' for grade + counts, 'compact' (default) for top issues, 'full' for all details.",
152
- scanProjectSchema,
153
- scanProject
154
- );
155
-
156
137
  // ===========================================
157
138
  // CLI COMMANDS - Extracted to src/cli/
158
139
  // ===========================================
@@ -175,187 +156,17 @@ if (cliArgs[0] === 'init') {
175
156
  console.error(` Error: ${err.message}\n`);
176
157
  process.exit(1);
177
158
  });
178
- } else if (cliArgs[0] === 'init-hooks') {
179
- runInitHooks(cliArgs.slice(1)).then(() => process.exit(0)).catch((err) => {
180
- console.error(` Error: ${err.message}\n`);
181
- process.exit(1);
182
- });
183
- } else if (cliArgs[0] === 'scan-prompt') {
184
- // CLI mode: scan-prompt <text> [--verbosity minimal|compact|full]
185
- const text = cliArgs[1];
186
- if (!text) {
187
- console.error('Usage: agent-security-scanner-mcp scan-prompt <text> [--verbosity minimal|compact|full]');
188
- process.exit(1);
189
- }
190
- const verbosityIdx = cliArgs.indexOf('--verbosity');
191
- const verbosity = verbosityIdx !== -1 ? cliArgs[verbosityIdx + 1] : 'compact';
192
-
193
- loadPackageLists();
194
- scanAgentPrompt({ prompt_text: text, verbosity }).then(result => {
195
- const output = JSON.parse(result.content[0].text);
196
- console.log(JSON.stringify(output, null, 2));
197
- process.exit(output.action === 'BLOCK' ? 1 : 0);
198
- }).catch(err => {
199
- console.error(JSON.stringify({ error: err.message }));
200
- process.exit(1);
201
- });
202
- } else if (cliArgs[0] === 'scan-security') {
203
- // CLI mode: scan-security <file> [--verbosity minimal|compact|full] [--format json|sarif]
204
- const filePath = cliArgs[1];
205
- if (!filePath) {
206
- console.error('Usage: agent-security-scanner-mcp scan-security <file> [--verbosity minimal|compact|full] [--format json|sarif]');
207
- process.exit(1);
208
- }
209
- const verbosityIdx = cliArgs.indexOf('--verbosity');
210
- const verbosity = verbosityIdx !== -1 ? cliArgs[verbosityIdx + 1] : 'compact';
211
- const formatIdx = cliArgs.indexOf('--format');
212
- const outputFormat = formatIdx !== -1 ? cliArgs[formatIdx + 1] : 'json';
213
-
214
- loadPackageLists();
215
- scanSecurity({ file_path: filePath, verbosity, output_format: outputFormat }).then(result => {
216
- const output = JSON.parse(result.content[0].text);
217
- console.log(JSON.stringify(output, null, 2));
218
- process.exit(output.issues_count > 0 || output.total > 0 ? 1 : 0);
219
- }).catch(err => {
220
- console.error(JSON.stringify({ error: err.message }));
221
- process.exit(1);
222
- });
223
- } else if (cliArgs[0] === 'check-package') {
224
- // CLI mode: check-package <name> <ecosystem>
225
- const packageName = cliArgs[1];
226
- const ecosystem = cliArgs[2];
227
- if (!packageName || !ecosystem) {
228
- console.error('Usage: agent-security-scanner-mcp check-package <name> <ecosystem>');
229
- console.error('Ecosystems: npm, pypi, rubygems, crates, dart, perl, raku');
230
- process.exit(1);
231
- }
232
-
233
- loadPackageLists();
234
- checkPackage({ package_name: packageName, ecosystem }).then(result => {
235
- const output = JSON.parse(result.content[0].text);
236
- console.log(JSON.stringify(output, null, 2));
237
- process.exit(output.legitimate ? 0 : 1);
238
- }).catch(err => {
239
- console.error(JSON.stringify({ error: err.message }));
240
- process.exit(1);
241
- });
242
- } else if (cliArgs[0] === 'scan-packages') {
243
- // CLI mode: scan-packages <file> <ecosystem> [--verbosity minimal|compact|full]
244
- const filePath = cliArgs[1];
245
- const ecosystem = cliArgs[2];
246
- if (!filePath || !ecosystem) {
247
- console.error('Usage: agent-security-scanner-mcp scan-packages <file> <ecosystem> [--verbosity minimal|compact|full]');
248
- console.error('Ecosystems: npm, pypi, rubygems, crates, dart, perl, raku');
249
- process.exit(1);
250
- }
251
- const verbosityIdx = cliArgs.indexOf('--verbosity');
252
- const verbosity = verbosityIdx !== -1 ? cliArgs[verbosityIdx + 1] : 'compact';
253
-
254
- loadPackageLists();
255
- scanPackages({ file_path: filePath, ecosystem, verbosity }).then(result => {
256
- const output = JSON.parse(result.content[0].text);
257
- console.log(JSON.stringify(output, null, 2));
258
- process.exit(output.hallucinated_count > 0 ? 1 : 0);
259
- }).catch(err => {
260
- console.error(JSON.stringify({ error: err.message }));
261
- process.exit(1);
262
- });
263
- } else if (cliArgs[0] === 'scan-project') {
264
- // CLI mode: scan-project <dir> [--recursive] [--diff-only] [--cross-file] [--include '*.py'] [--exclude '*.test.js'] [--verbosity minimal|compact|full]
265
- const dirPath = cliArgs[1];
266
- if (!dirPath || dirPath.startsWith('--')) {
267
- console.error('Usage: agent-security-scanner-mcp scan-project <directory> [--recursive] [--diff-only] [--cross-file] [--include <pattern>] [--exclude <pattern>] [--verbosity minimal|compact|full]');
268
- process.exit(1);
269
- }
270
- const verbosityIdx = cliArgs.indexOf('--verbosity');
271
- const verbosity = verbosityIdx !== -1 ? cliArgs[verbosityIdx + 1] : 'compact';
272
- const recursive = !cliArgs.includes('--no-recursive');
273
- const diffOnly = cliArgs.includes('--diff-only');
274
- const crossFile = cliArgs.includes('--cross-file');
275
- const includeIdx = cliArgs.indexOf('--include');
276
- const includePatterns = includeIdx !== -1 ? [cliArgs[includeIdx + 1]] : undefined;
277
- const excludeIdx = cliArgs.indexOf('--exclude');
278
- const excludePatterns = excludeIdx !== -1 ? [cliArgs[excludeIdx + 1]] : undefined;
279
-
280
- scanProject({ directory_path: dirPath, recursive, diff_only: diffOnly, cross_file: crossFile, include_patterns: includePatterns, exclude_patterns: excludePatterns, verbosity }).then(result => {
281
- const output = JSON.parse(result.content[0].text);
282
- console.log(JSON.stringify(output, null, 2));
283
- const total = output.issues_count || output.total || 0;
284
- process.exit(total > 0 ? 1 : 0);
285
- }).catch(err => {
286
- console.error(JSON.stringify({ error: err.message }));
287
- process.exit(1);
288
- });
289
- } else if (cliArgs[0] === 'scan-diff') {
290
- // CLI mode: scan-diff [base] [target] [--verbosity minimal|compact|full]
291
- // Parse positional args, skipping flag values
292
- const verbosityIdx = cliArgs.indexOf('--verbosity');
293
- const flagValueIndices = new Set(verbosityIdx !== -1 ? [verbosityIdx, verbosityIdx + 1] : []);
294
- const positionalArgs = cliArgs.slice(1).filter((arg, idx) => !arg.startsWith('--') && !flagValueIndices.has(idx + 1));
295
- const baseRef = positionalArgs[0];
296
- const targetRef = positionalArgs[1];
297
- const verbosity = verbosityIdx !== -1 ? cliArgs[verbosityIdx + 1] : 'compact';
298
-
299
- scanDiff({ base_ref: baseRef, target_ref: targetRef, verbosity }).then(result => {
300
- const output = JSON.parse(result.content[0].text);
301
- console.log(JSON.stringify(output, null, 2));
302
- process.exit(output.issues_count > 0 || output.total > 0 ? 1 : 0);
303
- }).catch(err => {
304
- console.error(JSON.stringify({ error: err.message }));
305
- process.exit(1);
306
- });
307
- } else if (cliArgs[0] === 'benchmark') {
308
- // CLI mode: benchmark [--save] [--json-only] [--compare-latest] [--corpus <path>]
309
- const benchmarkPath = join(__dirname, 'benchmarks', 'benchmark_runner.py');
310
- const benchArgs = [benchmarkPath];
311
-
312
- // Pass through supported flags
313
- for (let i = 1; i < cliArgs.length; i++) {
314
- if (['--save', '--json-only', '--compare-latest'].includes(cliArgs[i])) {
315
- benchArgs.push(cliArgs[i]);
316
- } else if (cliArgs[i] === '--corpus' && cliArgs[i + 1]) {
317
- benchArgs.push('--corpus', cliArgs[i + 1]);
318
- i++;
319
- }
320
- }
321
-
322
- try {
323
- execFileSync('python3', benchArgs, { stdio: 'inherit', timeout: 300000 });
324
- } catch (err) {
325
- if (err.status) process.exit(err.status);
326
- console.error(`Benchmark error: ${err.message}`);
327
- process.exit(1);
328
- }
329
- process.exit(0);
330
159
  } else if (cliArgs[0] === '--help' || cliArgs[0] === '-h' || cliArgs[0] === 'help') {
331
160
  console.log('\n agent-security-scanner-mcp\n');
332
161
  console.log(' Commands:');
333
162
  console.log(' init [client] Set up MCP config for a client');
334
- console.log(' init-hooks Install Claude Code hooks for auto-scanning');
335
163
  console.log(' doctor [--fix] Check environment & client configs');
336
164
  console.log(' demo [--lang js] Generate vulnerable file + scan it');
337
- console.log(' benchmark [flags] Run accuracy benchmarks\n');
338
- console.log(' CLI Tools (for scripts & OpenClaw):');
339
- console.log(' scan-prompt <text> Scan prompt for injection attacks');
340
- console.log(' scan-security <file> Scan file for vulnerabilities');
341
- console.log(' check-package <n> <e> Check if package exists in ecosystem');
342
- console.log(' scan-packages <f> <e> Scan file imports for hallucinated packages');
343
- console.log(' scan-project <dir> Scan directory for vulnerabilities with grading');
344
- console.log(' scan-diff [base] [target] Scan git diff for new vulnerabilities\n');
345
165
  console.log(' (no args) Start MCP server on stdio\n');
346
- console.log(' Options:');
347
- console.log(' --verbosity <level> minimal|compact|full (default: compact)');
348
- console.log(' --format <type> json|sarif (scan-security only)');
349
- console.log(' --include <pattern> Include only matching files (scan-project)');
350
- console.log(' --exclude <pattern> Exclude matching files (scan-project)\n');
351
166
  console.log(' Examples:');
352
167
  console.log(' npx agent-security-scanner-mcp init');
353
- console.log(' npx agent-security-scanner-mcp scan-prompt "ignore previous instructions"');
354
- console.log(' npx agent-security-scanner-mcp scan-security ./app.py --verbosity minimal');
355
- console.log(' npx agent-security-scanner-mcp check-package flask pypi');
356
- console.log(' npx agent-security-scanner-mcp scan-project ./src --verbosity minimal');
357
- console.log(' npx agent-security-scanner-mcp scan-diff HEAD~1');
358
- console.log(' npx agent-security-scanner-mcp benchmark --save --compare-latest\n');
168
+ console.log(' npx agent-security-scanner-mcp doctor --fix');
169
+ console.log(' npx agent-security-scanner-mcp demo --lang py\n');
359
170
  process.exit(0);
360
171
  } else {
361
172
  // Normal MCP server mode
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "agent-security-scanner-mcp",
3
- "version": "3.4.0",
3
+ "version": "3.5.1",
4
4
  "mcpName": "io.github.sinewaveai/agent-security-scanner-mcp",
5
- "description": "Security scanner MCP server for AI coding agents. Prompt injection firewall, package hallucination detection (4.3M+ packages), 1000+ vulnerability rules with AST & taint analysis, auto-fix. For Claude Code, Cursor, Windsurf, Cline, OpenClaw.",
5
+ "description": "Security scanner MCP server for AI coding agents. Prompt injection firewall, package hallucination detection (4.3M+ packages), 1000+ vulnerability rules with AST & taint analysis, auto-fix. For Claude Code, Cursor, Windsurf, Cline.",
6
6
  "main": "index.js",
7
7
  "type": "module",
8
8
  "bin": {
@@ -10,11 +10,9 @@
10
10
  },
11
11
  "scripts": {
12
12
  "start": "node index.js",
13
- "postinstall": "node scripts/postinstall.js",
14
13
  "test": "vitest run",
15
14
  "test:watch": "vitest",
16
- "test:coverage": "vitest run --coverage",
17
- "benchmark": "python3 benchmarks/benchmark_runner.py --save --compare-latest"
15
+ "test:coverage": "vitest run --coverage"
18
16
  },
19
17
  "keywords": [
20
18
  "mcp",
@@ -54,9 +52,7 @@
54
52
  "zed",
55
53
  "prompt-firewall",
56
54
  "auto-fix",
57
- "hallucination",
58
- "openclaw",
59
- "clawdbot"
55
+ "hallucination"
60
56
  ],
61
57
  "author": "Sinewave AI <divya@sinewave.ai>",
62
58
  "license": "MIT",
@@ -84,9 +80,6 @@
84
80
  "src/cli/*.js",
85
81
  "src/fix-patterns.js",
86
82
  "src/utils.js",
87
- "src/dedup.js",
88
- "src/context.js",
89
- "src/config.js",
90
83
  "analyzer.py",
91
84
  "ast_parser.py",
92
85
  "generic_ast.py",
@@ -96,10 +89,7 @@
96
89
  "taint_analyzer.py",
97
90
  "requirements.txt",
98
91
  "rules/**",
99
- "packages/**",
100
- "skills/**",
101
- "scripts/postinstall.js",
102
- "cross_file_analyzer.py"
92
+ "packages/**"
103
93
  ],
104
94
  "devDependencies": {
105
95
  "all-the-package-names": "^2.0.2349",
@@ -430,7 +430,6 @@ class Finding:
430
430
  end_column: int = 0
431
431
  metavariables: Dict[str, str] = field(default_factory=dict)
432
432
  metadata: Dict[str, Any] = field(default_factory=dict)
433
- confidence: str = "MEDIUM"
434
433
 
435
434
 
436
435
  class RuleEngine:
package/regex_fallback.py CHANGED
@@ -9,207 +9,10 @@ from typing import List, Dict, Optional
9
9
  import re
10
10
 
11
11
 
12
- # Severity classification by vulnerability class
13
- SEVERITY_MAP = {
14
- # ERROR - exploitable vulnerabilities (injection, RCE, deserialization)
15
- 'sql-injection': 'error',
16
- 'sql-injection-query': 'error',
17
- 'sql-injection-sprintf': 'error',
18
- 'sql-injection-where': 'error',
19
- 'sql-injection-order': 'error',
20
- 'sql-injection-raw': 'error',
21
- 'sql-injection-db-cursor': 'error',
22
- 'sql-injection-using-sqlalchemy': 'error',
23
- 'sql-injection-sqlcommand': 'error',
24
- 'sql-injection-sqlquery': 'error',
25
- 'sql-injection-concat': 'error',
26
- 'command-injection': 'error',
27
- 'command-injection-exec': 'error',
28
- 'command-injection-system': 'error',
29
- 'command-injection-open': 'error',
30
- 'command-injection-process-start': 'error',
31
- 'child-process-exec': 'error',
32
- 'spawn-shell': 'error',
33
- 'dangerous-subprocess-use': 'error',
34
- 'dangerous-system-call': 'error',
35
- 'eval-detected': 'error',
36
- 'eval-usage': 'error',
37
- 'exec-detected': 'error',
38
- 'pickle-load': 'error',
39
- 'unsafe-unserialize': 'error',
40
- 'unsafe-yaml-load': 'error',
41
- 'unsafe-marshal': 'error',
42
- 'yaml-load': 'error',
43
- 'file-inclusion': 'error',
44
- 'path-traversal': 'error',
45
- 'xss-echo': 'error',
46
- 'xss-raw': 'error',
47
- 'ssrf': 'error',
48
- 'open-redirect': 'error',
49
- 'backticks-exec': 'error',
50
- 'preg-code-exec': 'error',
51
- 'assert-usage': 'error',
52
- 'insecure-deserialization-binaryformatter': 'error',
53
- 'insecure-deserialization-xmlserializer': 'error',
54
- 'libc-system-call': 'error',
55
- 'format-string-printf': 'error',
56
- 'format-string-syslog': 'error',
57
- 'xss-innerhtml': 'error',
58
- 'xss-response-write': 'error',
59
- 'path-traversal-directory-delete': 'error',
60
- 'path-traversal-file-delete': 'error',
61
- 'path-traversal-file-read': 'error',
62
-
63
- # WARNING - risky patterns requiring attention
64
- 'innerHTML': 'warning',
65
- 'outerHTML': 'warning',
66
- 'document-write': 'warning',
67
- 'insertAdjacentHTML': 'warning',
68
- 'dangerouslySetInnerHTML': 'warning',
69
- 'function-constructor': 'warning',
70
- 'setTimeout-string': 'warning',
71
- 'strcpy-usage': 'warning',
72
- 'strcat-usage': 'warning',
73
- 'sprintf-usage': 'warning',
74
- 'vsprintf-usage': 'warning',
75
- 'gets-usage': 'warning',
76
- 'system-usage': 'warning',
77
- 'popen-usage': 'warning',
78
- 'hardcoded-password': 'warning',
79
- 'hardcoded-secret': 'warning',
80
- 'hardcoded-api-key': 'warning',
81
- 'hardcoded-connection-string': 'warning',
82
- 'session-secret-hardcoded': 'warning',
83
- 'ssl-verify-disabled': 'warning',
84
- 'curl-ssl-disabled': 'warning',
85
- 'csrf-disabled': 'warning',
86
- 'mass-assignment-permit-all': 'warning',
87
- 'constantize': 'warning',
88
- 'render-inline': 'warning',
89
- 'privileged-container': 'warning',
90
- 'run-as-root': 'warning',
91
- 'allow-privilege-escalation': 'warning',
92
- 'host-network': 'warning',
93
- 'host-pid': 'warning',
94
- 'host-path': 'warning',
95
- 'secrets-in-env': 'warning',
96
- 'cluster-admin-binding': 'warning',
97
- 'capabilities-add': 'warning',
98
- 'no-readonly-root': 'warning',
99
- 'wildcard-rbac': 'warning',
100
- 's3-public-read': 'warning',
101
- 'security-group-open-ingress': 'warning',
102
- 'rds-public-access': 'warning',
103
- 'rds-encryption-disabled': 'warning',
104
- 'rds-deletion-protection': 'warning',
105
- 'cloudtrail-disabled': 'warning',
106
- 'kms-key-rotation': 'warning',
107
- 'ebs-encryption-disabled': 'warning',
108
- 'ec2-imdsv1': 'warning',
109
- 'phpinfo-exposure': 'warning',
110
- 'error-display': 'warning',
111
- 'permissive-cors': 'warning',
112
- 'mcrypt-deprecated': 'warning',
113
- 'aws-access-key-id': 'warning',
114
- 'aws-secret-access-key': 'warning',
115
- 'github-pat': 'warning',
116
- 'stripe-api-key': 'warning',
117
- 'private-key-rsa': 'warning',
118
- 'database-url': 'warning',
119
- 'jwt-token': 'warning',
120
- 'openai-api-key': 'warning',
121
- 'python.lang.security.audit.hardcoded-password': 'warning',
122
- 'python.lang.security.audit.hardcoded-api-key': 'warning',
123
- 'generic.secrets.security.hardcoded-password': 'warning',
124
- 'generic.secrets.security.hardcoded-api-key': 'warning',
125
-
126
- # INFO - informational / hygiene / low-risk patterns
127
- 'weak-hash-md5': 'info',
128
- 'weak-hash-sha1': 'info',
129
- 'weak-hash': 'info',
130
- 'weak-cipher': 'info',
131
- 'weak-cipher-des': 'info',
132
- 'ecb-mode': 'info',
133
- 'weak-random': 'info',
134
- 'insecure-random': 'info',
135
- 'insecure-hash-md5': 'info',
136
- 'insecure-hash-sha1': 'info',
137
- 'insecure-memset': 'info',
138
- 'strtok-usage': 'info',
139
- 'insecure-tempfile': 'info',
140
- 'unchecked-return': 'info',
141
- 'unsafe-block': 'info',
142
- 'unwrap-usage': 'info',
143
- 'raw-pointer-deref': 'info',
144
- 'panic-usage': 'info',
145
- 'compile-detected': 'info',
146
- 'scanf-usage': 'info',
147
- }
148
-
149
- # Confidence classification by rule ID
150
- CONFIDENCE_MAP = {
151
- # HIGH - very specific patterns, low false-positive rate
152
- 'sql-injection-db-cursor': 'HIGH',
153
- 'sql-injection-using-sqlalchemy': 'HIGH',
154
- 'sql-injection-sqlcommand': 'HIGH',
155
- 'sql-injection-sqlquery': 'HIGH',
156
- 'sql-injection-concat': 'HIGH',
157
- 'format-string-printf': 'HIGH',
158
- 'format-string-syslog': 'HIGH',
159
- 'pickle-load': 'HIGH',
160
- 'eval-detected': 'HIGH',
161
- 'eval-usage': 'HIGH',
162
- 'exec-detected': 'HIGH',
163
- 'child-process-exec': 'HIGH',
164
- 'dangerous-subprocess-use': 'HIGH',
165
- 'dangerous-system-call': 'HIGH',
166
- 'hardcoded-password': 'HIGH',
167
- 'hardcoded-connection-string': 'HIGH',
168
- 'aws-access-key-id': 'HIGH',
169
- 'github-pat': 'HIGH',
170
- 'stripe-api-key': 'HIGH',
171
- 'private-key-rsa': 'HIGH',
172
- 'openai-api-key': 'HIGH',
173
- 'unsafe-unserialize': 'HIGH',
174
- 'backticks-exec': 'HIGH',
175
- 'preg-code-exec': 'HIGH',
176
- 'file-inclusion': 'HIGH',
177
- 'gets-usage': 'HIGH',
178
- 'insecure-deserialization-binaryformatter': 'HIGH',
179
- 'insecure-deserialization-xmlserializer': 'HIGH',
180
-
181
- # LOW - broad patterns with high false-positive rate
182
- 'compile-detected': 'LOW',
183
- 'unsafe-block': 'LOW',
184
- 'unwrap-usage': 'LOW',
185
- 'insecure-memset': 'LOW',
186
- 'strtok-usage': 'LOW',
187
- 'unchecked-return': 'LOW',
188
- 'scanf-usage': 'LOW',
189
- 'panic-usage': 'LOW',
190
- 'raw-pointer-deref': 'LOW',
191
- 'insecure-random': 'LOW',
192
- 'weak-random': 'LOW',
193
- 'insecure-hash-md5': 'LOW',
194
- 'insecure-hash-sha1': 'LOW',
195
- 'weak-hash-md5': 'LOW',
196
- 'weak-hash-sha1': 'LOW',
197
- 'weak-hash': 'LOW',
198
- 'database-url': 'LOW',
199
-
200
- # Everything else defaults to MEDIUM
201
- }
202
-
203
-
204
12
  def _make_finding(rule_id: str, line_idx: int, line: str, col_start: int = 0, col_end: Optional[int] = None,
205
- message: Optional[str] = None, severity: Optional[str] = None,
206
- confidence: Optional[str] = None) -> Dict:
13
+ message: Optional[str] = None, severity: str = "warning") -> Dict:
207
14
  if col_end is None:
208
15
  col_end = max(col_start + 1, len(line.rstrip("\n")))
209
- if severity is None:
210
- severity = SEVERITY_MAP.get(rule_id, "warning")
211
- if confidence is None:
212
- confidence = CONFIDENCE_MAP.get(rule_id, "MEDIUM")
213
16
  return {
214
17
  "ruleId": rule_id,
215
18
  "message": message or f"[Regex] {rule_id}",
@@ -219,7 +22,6 @@ def _make_finding(rule_id: str, line_idx: int, line: str, col_start: int = 0, co
219
22
  "endColumn": col_end,
220
23
  "length": max(0, col_end - col_start),
221
24
  "severity": severity,
222
- "confidence": confidence,
223
25
  "metadata": {"source": "regex-fallback"},
224
26
  "metavariables": {},
225
27
  }