@empowered-humanity/agent-security 1.0.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 +295 -0
- package/SECURITY.md +96 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +200 -0
- package/dist/index.js.map +1 -0
- package/dist/patterns/agent-attacks.d.ts +53 -0
- package/dist/patterns/agent-attacks.d.ts.map +1 -0
- package/dist/patterns/agent-attacks.js +304 -0
- package/dist/patterns/agent-attacks.js.map +1 -0
- package/dist/patterns/credentials.d.ts +30 -0
- package/dist/patterns/credentials.d.ts.map +1 -0
- package/dist/patterns/credentials.js +231 -0
- package/dist/patterns/credentials.js.map +1 -0
- package/dist/patterns/defense-evasion.d.ts +39 -0
- package/dist/patterns/defense-evasion.d.ts.map +1 -0
- package/dist/patterns/defense-evasion.js +193 -0
- package/dist/patterns/defense-evasion.js.map +1 -0
- package/dist/patterns/index.d.ts +73 -0
- package/dist/patterns/index.d.ts.map +1 -0
- package/dist/patterns/index.js +114 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/patterns/injection.d.ts +68 -0
- package/dist/patterns/injection.d.ts.map +1 -0
- package/dist/patterns/injection.js +398 -0
- package/dist/patterns/injection.js.map +1 -0
- package/dist/patterns/mcp-checklist.d.ts +30 -0
- package/dist/patterns/mcp-checklist.d.ts.map +1 -0
- package/dist/patterns/mcp-checklist.js +559 -0
- package/dist/patterns/mcp-checklist.js.map +1 -0
- package/dist/patterns/owasp-asi.d.ts +79 -0
- package/dist/patterns/owasp-asi.d.ts.map +1 -0
- package/dist/patterns/owasp-asi.js +274 -0
- package/dist/patterns/owasp-asi.js.map +1 -0
- package/dist/patterns/rce.d.ts +44 -0
- package/dist/patterns/rce.d.ts.map +1 -0
- package/dist/patterns/rce.js +276 -0
- package/dist/patterns/rce.js.map +1 -0
- package/dist/patterns/types.d.ts +134 -0
- package/dist/patterns/types.d.ts.map +1 -0
- package/dist/patterns/types.js +8 -0
- package/dist/patterns/types.js.map +1 -0
- package/dist/reporters/console.d.ts +31 -0
- package/dist/reporters/console.d.ts.map +1 -0
- package/dist/reporters/console.js +147 -0
- package/dist/reporters/console.js.map +1 -0
- package/dist/reporters/index.d.ts +6 -0
- package/dist/reporters/index.d.ts.map +1 -0
- package/dist/reporters/index.js +6 -0
- package/dist/reporters/index.js.map +1 -0
- package/dist/reporters/json.d.ts +19 -0
- package/dist/reporters/json.d.ts.map +1 -0
- package/dist/reporters/json.js +74 -0
- package/dist/reporters/json.js.map +1 -0
- package/dist/scanner/content-scanner.d.ts +40 -0
- package/dist/scanner/content-scanner.d.ts.map +1 -0
- package/dist/scanner/content-scanner.js +101 -0
- package/dist/scanner/content-scanner.js.map +1 -0
- package/dist/scanner/engine.d.ts +38 -0
- package/dist/scanner/engine.d.ts.map +1 -0
- package/dist/scanner/engine.js +373 -0
- package/dist/scanner/engine.js.map +1 -0
- package/dist/scanner/index.d.ts +6 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +6 -0
- package/dist/scanner/index.js.map +1 -0
- package/package.json +88 -0
- package/sbom.json +107 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Security Pattern Types
|
|
3
|
+
*
|
|
4
|
+
* Defines the core interfaces for detection patterns used throughout
|
|
5
|
+
* the agent-security scanner.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Severity levels for security findings
|
|
9
|
+
*/
|
|
10
|
+
export type Severity = 'critical' | 'high' | 'medium' | 'low';
|
|
11
|
+
/**
|
|
12
|
+
* Finding classification — WHY this finding exists
|
|
13
|
+
*/
|
|
14
|
+
export type FindingClassification = 'test_payload' | 'live_vulnerability' | 'credential_exposure' | 'configuration_risk' | 'architectural_weakness' | 'supply_chain_risk' | 'unclassified';
|
|
15
|
+
/**
|
|
16
|
+
* Taint proximity — how close a dangerous sink is to untrusted input
|
|
17
|
+
*/
|
|
18
|
+
export type TaintProximity = 'direct' | 'nearby' | 'distant' | 'unknown';
|
|
19
|
+
/**
|
|
20
|
+
* Attack categories based on research sources
|
|
21
|
+
*/
|
|
22
|
+
export type AttackCategory = 'instruction_override' | 'role_manipulation' | 'boundary_escape' | 'data_exfiltration' | 'dangerous_commands' | 'hidden_injection' | 'stealth_instruction' | 'url_reconstruction' | 'credential_theft' | 'credential_exposure' | 'cross_agent_escalation' | 'mcp_attack' | 'rag_poisoning' | 'persistence' | 'goal_hijacking' | 'session_smuggling' | 'argument_injection' | 'code_injection' | 'ssrf' | 'reconnaissance' | 'prompt_extraction' | 'defense_evasion' | 'hierarchy_violation' | 'adversarial_suffix' | 'ASI01_goal_hijack' | 'ASI02_tool_misuse' | 'ASI03_privilege_abuse' | 'ASI04_supply_chain' | 'ASI05_rce' | 'ASI06_memory_poisoning' | 'ASI07_insecure_comms' | 'ASI08_cascading_failures' | 'ASI09_trust_exploitation' | 'ASI10_rogue_agents' | 'config_vulnerability' | 'permission_escalation' | 'behavior_manipulation' | 'platform_specific' | 'rendering_exfil' | 'path_traversal';
|
|
23
|
+
/**
|
|
24
|
+
* Research source identifiers
|
|
25
|
+
*/
|
|
26
|
+
export type SourceId = 'ai-assistant' | 'ACAD-001' | 'ACAD-004' | 'PII-001' | 'PII-002' | 'PII-004' | 'PIC-001' | 'PIC-004' | 'PIC-005' | 'FND-001' | 'THR-002' | 'THR-003' | 'THR-004' | 'THR-005' | 'THR-006' | 'FRM-002' | 'VND-005' | 'CMP-002' | 'SLOWMIST-MCP' | 'custom';
|
|
27
|
+
/**
|
|
28
|
+
* Context where the pattern should be matched
|
|
29
|
+
*/
|
|
30
|
+
export type MatchContext = 'any' | 'prompt' | 'code' | 'config' | 'file_path' | 'file_write_operation' | 'file_create' | 'outbound_request' | 'email_operation' | 'url_parameter' | 'generated_code' | 'command_template' | 'user_input' | 'dependency_version';
|
|
31
|
+
/**
|
|
32
|
+
* A detection pattern for security scanning
|
|
33
|
+
*/
|
|
34
|
+
export interface DetectionPattern {
|
|
35
|
+
/** Unique identifier for this pattern */
|
|
36
|
+
name: string;
|
|
37
|
+
/** Regular expression to match */
|
|
38
|
+
pattern: RegExp;
|
|
39
|
+
/** Severity of a match */
|
|
40
|
+
severity: Severity;
|
|
41
|
+
/** Attack category */
|
|
42
|
+
category: AttackCategory;
|
|
43
|
+
/** Research source this pattern came from */
|
|
44
|
+
source: SourceId;
|
|
45
|
+
/** Human-readable description */
|
|
46
|
+
description: string;
|
|
47
|
+
/** Context where this pattern is most relevant */
|
|
48
|
+
context?: MatchContext;
|
|
49
|
+
/** Tags for filtering */
|
|
50
|
+
tags?: string[];
|
|
51
|
+
/** OWASP ASI ID if applicable */
|
|
52
|
+
owaspAsi?: string;
|
|
53
|
+
/** CVE reference if applicable */
|
|
54
|
+
cve?: string;
|
|
55
|
+
/** Example of what this pattern catches */
|
|
56
|
+
example?: string;
|
|
57
|
+
/** Remediation guidance */
|
|
58
|
+
remediation?: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* A security finding from pattern matching
|
|
62
|
+
*/
|
|
63
|
+
export interface Finding {
|
|
64
|
+
/** Pattern that matched */
|
|
65
|
+
pattern: DetectionPattern;
|
|
66
|
+
/** File where finding occurred */
|
|
67
|
+
file: string;
|
|
68
|
+
/** Line number (1-indexed) */
|
|
69
|
+
line: number;
|
|
70
|
+
/** Column number (1-indexed) */
|
|
71
|
+
column: number;
|
|
72
|
+
/** The matched text */
|
|
73
|
+
match: string;
|
|
74
|
+
/** Surrounding context */
|
|
75
|
+
context: string;
|
|
76
|
+
/** Timestamp */
|
|
77
|
+
timestamp: Date;
|
|
78
|
+
/** Auto-classification of why this finding exists */
|
|
79
|
+
classification: FindingClassification;
|
|
80
|
+
/** Original severity before any contextual adjustment */
|
|
81
|
+
originalSeverity: Severity;
|
|
82
|
+
/** Whether severity was downgraded (e.g., test file) */
|
|
83
|
+
severityDowngraded: boolean;
|
|
84
|
+
/** Whether this finding is in a test file */
|
|
85
|
+
isTestFile: boolean;
|
|
86
|
+
/** Taint proximity for dangerous sink patterns */
|
|
87
|
+
taintProximity?: TaintProximity;
|
|
88
|
+
/** Context flow chain (for architectural findings) */
|
|
89
|
+
contextFlowChain?: string[];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Risk score calculation result
|
|
93
|
+
*/
|
|
94
|
+
export interface RiskScore {
|
|
95
|
+
/** Total score 0-100 (higher is safer) */
|
|
96
|
+
total: number;
|
|
97
|
+
/** Risk level */
|
|
98
|
+
level: 'critical' | 'high' | 'moderate' | 'low';
|
|
99
|
+
/** Count by severity */
|
|
100
|
+
counts: {
|
|
101
|
+
critical: number;
|
|
102
|
+
high: number;
|
|
103
|
+
medium: number;
|
|
104
|
+
low: number;
|
|
105
|
+
};
|
|
106
|
+
/** OWASP ASI compliance percentage */
|
|
107
|
+
owaspCompliance: number;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Scan result
|
|
111
|
+
*/
|
|
112
|
+
export interface ScanResult {
|
|
113
|
+
/** Files scanned */
|
|
114
|
+
filesScanned: number;
|
|
115
|
+
/** Total patterns checked */
|
|
116
|
+
patternsChecked: number;
|
|
117
|
+
/** All findings */
|
|
118
|
+
findings: Finding[];
|
|
119
|
+
/** Risk score */
|
|
120
|
+
riskScore: RiskScore;
|
|
121
|
+
/** Scan duration in ms */
|
|
122
|
+
duration: number;
|
|
123
|
+
/** Timestamp */
|
|
124
|
+
timestamp: Date;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Pattern category grouping for organization
|
|
128
|
+
*/
|
|
129
|
+
export interface PatternCategory {
|
|
130
|
+
name: string;
|
|
131
|
+
description: string;
|
|
132
|
+
patterns: DetectionPattern[];
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/patterns/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/patterns/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console Reporter
|
|
3
|
+
*
|
|
4
|
+
* Formats scan results for terminal output with colors.
|
|
5
|
+
*/
|
|
6
|
+
import type { Finding, ScanResult } from '../patterns/types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Format a single finding for console output
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatFinding(finding: Finding, showContext?: boolean): string;
|
|
11
|
+
/**
|
|
12
|
+
* Format the risk score for console output
|
|
13
|
+
*/
|
|
14
|
+
export declare function formatRiskScore(result: ScanResult): string;
|
|
15
|
+
/**
|
|
16
|
+
* Format the full scan result for console output
|
|
17
|
+
*/
|
|
18
|
+
export declare function formatScanResult(result: ScanResult, options?: {
|
|
19
|
+
showContext?: boolean;
|
|
20
|
+
groupBy?: 'file' | 'category' | 'severity';
|
|
21
|
+
verbose?: boolean;
|
|
22
|
+
}): string;
|
|
23
|
+
/**
|
|
24
|
+
* Print scan result to console
|
|
25
|
+
*/
|
|
26
|
+
export declare function printScanResult(result: ScanResult, options?: {
|
|
27
|
+
showContext?: boolean;
|
|
28
|
+
groupBy?: 'file' | 'category' | 'severity';
|
|
29
|
+
verbose?: boolean;
|
|
30
|
+
}): void;
|
|
31
|
+
//# sourceMappingURL=console.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/reporters/console.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAY,MAAM,sBAAsB,CAAC;AAiB1E;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,UAAQ,GAAG,MAAM,CA+B3E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA+B1D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,GAAE;IAC5D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;CACd,GAAG,MAAM,CAgEd;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,GAAE;IAC3D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;CACd,GAAG,IAAI,CAEZ"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console Reporter
|
|
3
|
+
*
|
|
4
|
+
* Formats scan results for terminal output with colors.
|
|
5
|
+
*/
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { groupFindingsByFile, groupFindingsByCategory } from '../scanner/engine.js';
|
|
8
|
+
const SEVERITY_COLORS = {
|
|
9
|
+
critical: chalk.bgRed.white.bold,
|
|
10
|
+
high: chalk.red.bold,
|
|
11
|
+
medium: chalk.yellow,
|
|
12
|
+
low: chalk.blue,
|
|
13
|
+
};
|
|
14
|
+
const SEVERITY_ICONS = {
|
|
15
|
+
critical: '🚨',
|
|
16
|
+
high: '❌',
|
|
17
|
+
medium: '⚠️',
|
|
18
|
+
low: 'ℹ️',
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Format a single finding for console output
|
|
22
|
+
*/
|
|
23
|
+
export function formatFinding(finding, showContext = false) {
|
|
24
|
+
const { pattern, file, line, column, match } = finding;
|
|
25
|
+
const severityColor = SEVERITY_COLORS[pattern.severity];
|
|
26
|
+
const icon = SEVERITY_ICONS[pattern.severity];
|
|
27
|
+
let output = `${icon} ${severityColor(`[${pattern.severity.toUpperCase()}]`)} ${chalk.cyan(pattern.name)}\n`;
|
|
28
|
+
output += ` ${chalk.gray('File:')} ${file}:${line}:${column}\n`;
|
|
29
|
+
output += ` ${chalk.gray('Match:')} ${chalk.white(match)}\n`;
|
|
30
|
+
output += ` ${chalk.gray('Description:')} ${pattern.description}\n`;
|
|
31
|
+
if (pattern.owaspAsi) {
|
|
32
|
+
output += ` ${chalk.gray('OWASP ASI:')} ${chalk.magenta(pattern.owaspAsi)}\n`;
|
|
33
|
+
}
|
|
34
|
+
if (pattern.cve) {
|
|
35
|
+
output += ` ${chalk.gray('CVE:')} ${chalk.red(pattern.cve)}\n`;
|
|
36
|
+
}
|
|
37
|
+
if (pattern.remediation) {
|
|
38
|
+
output += ` ${chalk.gray('Remediation:')} ${chalk.green(pattern.remediation)}\n`;
|
|
39
|
+
}
|
|
40
|
+
if (showContext && finding.context) {
|
|
41
|
+
output += ` ${chalk.gray('Context:')}\n`;
|
|
42
|
+
const lines = finding.context.split('\n');
|
|
43
|
+
for (const contextLine of lines) {
|
|
44
|
+
output += ` ${chalk.dim('│')} ${contextLine}\n`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return output;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Format the risk score for console output
|
|
51
|
+
*/
|
|
52
|
+
export function formatRiskScore(result) {
|
|
53
|
+
const { riskScore } = result;
|
|
54
|
+
let levelColor;
|
|
55
|
+
switch (riskScore.level) {
|
|
56
|
+
case 'critical':
|
|
57
|
+
levelColor = chalk.bgRed.white.bold;
|
|
58
|
+
break;
|
|
59
|
+
case 'high':
|
|
60
|
+
levelColor = chalk.red.bold;
|
|
61
|
+
break;
|
|
62
|
+
case 'moderate':
|
|
63
|
+
levelColor = chalk.yellow.bold;
|
|
64
|
+
break;
|
|
65
|
+
case 'low':
|
|
66
|
+
levelColor = chalk.green.bold;
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
let output = chalk.bold('\n📊 Risk Assessment\n');
|
|
70
|
+
output += `${chalk.gray('═'.repeat(40))}\n`;
|
|
71
|
+
output += `Risk Score: ${levelColor(`${riskScore.total}/100`)} (${levelColor(riskScore.level.toUpperCase())})\n`;
|
|
72
|
+
output += `OWASP Compliance: ${riskScore.owaspCompliance >= 80 ? chalk.green : chalk.red}(${riskScore.owaspCompliance}%)\n\n`;
|
|
73
|
+
output += chalk.bold('Findings by Severity:\n');
|
|
74
|
+
output += ` ${SEVERITY_ICONS.critical} Critical: ${chalk.red.bold(riskScore.counts.critical.toString())}\n`;
|
|
75
|
+
output += ` ${SEVERITY_ICONS.high} High: ${chalk.red(riskScore.counts.high.toString())}\n`;
|
|
76
|
+
output += ` ${SEVERITY_ICONS.medium} Medium: ${chalk.yellow(riskScore.counts.medium.toString())}\n`;
|
|
77
|
+
output += ` ${SEVERITY_ICONS.low} Low: ${chalk.blue(riskScore.counts.low.toString())}\n`;
|
|
78
|
+
return output;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Format the full scan result for console output
|
|
82
|
+
*/
|
|
83
|
+
export function formatScanResult(result, options = {}) {
|
|
84
|
+
const { showContext = false, groupBy = 'severity', verbose = false } = options;
|
|
85
|
+
let output = '';
|
|
86
|
+
// Header
|
|
87
|
+
output += chalk.bold.cyan('\n🔍 Agent Security Scan Results\n');
|
|
88
|
+
output += chalk.gray('═'.repeat(50)) + '\n\n';
|
|
89
|
+
// Summary
|
|
90
|
+
output += `Files scanned: ${chalk.cyan(result.filesScanned.toString())}\n`;
|
|
91
|
+
output += `Patterns checked: ${chalk.cyan(result.patternsChecked.toString())}\n`;
|
|
92
|
+
output += `Duration: ${chalk.cyan(`${result.duration}ms`)}\n`;
|
|
93
|
+
output += `Total findings: ${chalk.cyan(result.findings.length.toString())}\n\n`;
|
|
94
|
+
if (result.findings.length === 0) {
|
|
95
|
+
output += chalk.green.bold('✅ No security issues found!\n');
|
|
96
|
+
return output;
|
|
97
|
+
}
|
|
98
|
+
// Findings
|
|
99
|
+
output += chalk.bold('📋 Findings\n');
|
|
100
|
+
output += chalk.gray('─'.repeat(40)) + '\n\n';
|
|
101
|
+
if (groupBy === 'file') {
|
|
102
|
+
const byFile = groupFindingsByFile(result.findings);
|
|
103
|
+
for (const [file, findings] of byFile) {
|
|
104
|
+
output += chalk.bold.underline(`\n${file}\n`);
|
|
105
|
+
for (const finding of findings) {
|
|
106
|
+
output += formatFinding(finding, showContext) + '\n';
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else if (groupBy === 'category') {
|
|
111
|
+
const byCategory = groupFindingsByCategory(result.findings);
|
|
112
|
+
for (const [category, findings] of byCategory) {
|
|
113
|
+
output += chalk.bold.underline(`\n${category} (${findings.length})\n`);
|
|
114
|
+
for (const finding of findings) {
|
|
115
|
+
output += formatFinding(finding, showContext) + '\n';
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// Group by severity (default)
|
|
121
|
+
for (const severity of ['critical', 'high', 'medium', 'low']) {
|
|
122
|
+
const findings = result.findings.filter((f) => f.pattern.severity === severity);
|
|
123
|
+
if (findings.length > 0) {
|
|
124
|
+
output += chalk.bold(`\n${SEVERITY_COLORS[severity](severity.toUpperCase())} (${findings.length})\n`);
|
|
125
|
+
for (const finding of findings) {
|
|
126
|
+
output += formatFinding(finding, showContext) + '\n';
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Risk score
|
|
132
|
+
output += formatRiskScore(result);
|
|
133
|
+
// Recommendations
|
|
134
|
+
if (result.riskScore.level === 'critical' || result.riskScore.level === 'high') {
|
|
135
|
+
output += chalk.bold.red('\n⚠️ Action Required\n');
|
|
136
|
+
output += chalk.red('This codebase has significant security vulnerabilities.\n');
|
|
137
|
+
output += chalk.red('Address critical and high severity findings before deployment.\n');
|
|
138
|
+
}
|
|
139
|
+
return output;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Print scan result to console
|
|
143
|
+
*/
|
|
144
|
+
export function printScanResult(result, options = {}) {
|
|
145
|
+
console.log(formatScanResult(result, options));
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=console.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console.js","sourceRoot":"","sources":["../../src/reporters/console.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reporters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/reporters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Reporter
|
|
3
|
+
*
|
|
4
|
+
* Outputs scan results in JSON format for programmatic consumption.
|
|
5
|
+
*/
|
|
6
|
+
import type { ScanResult } from '../patterns/types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Format scan result as JSON string
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatAsJson(result: ScanResult, pretty?: boolean): string;
|
|
11
|
+
/**
|
|
12
|
+
* Get findings summary as JSON object
|
|
13
|
+
*/
|
|
14
|
+
export declare function getFindingsSummary(result: ScanResult): object;
|
|
15
|
+
/**
|
|
16
|
+
* Print JSON to console
|
|
17
|
+
*/
|
|
18
|
+
export declare function printJson(result: ScanResult, pretty?: boolean): void;
|
|
19
|
+
//# sourceMappingURL=json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/reporters/json.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAW,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAwBhE;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,UAAO,GAAG,MAAM,CAmBtE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAiB7D;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,UAAO,GAAG,IAAI,CAEjE"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Reporter
|
|
3
|
+
*
|
|
4
|
+
* Outputs scan results in JSON format for programmatic consumption.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Serialize a finding to JSON-safe object
|
|
8
|
+
*/
|
|
9
|
+
function serializeFinding(finding) {
|
|
10
|
+
return {
|
|
11
|
+
patternName: finding.pattern.name,
|
|
12
|
+
severity: finding.pattern.severity,
|
|
13
|
+
category: finding.pattern.category,
|
|
14
|
+
description: finding.pattern.description,
|
|
15
|
+
file: finding.file,
|
|
16
|
+
line: finding.line,
|
|
17
|
+
column: finding.column,
|
|
18
|
+
match: finding.match,
|
|
19
|
+
context: finding.context,
|
|
20
|
+
source: finding.pattern.source,
|
|
21
|
+
owaspAsi: finding.pattern.owaspAsi || null,
|
|
22
|
+
cve: finding.pattern.cve || null,
|
|
23
|
+
remediation: finding.pattern.remediation || null,
|
|
24
|
+
timestamp: finding.timestamp.toISOString(),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Format scan result as JSON string
|
|
29
|
+
*/
|
|
30
|
+
export function formatAsJson(result, pretty = true) {
|
|
31
|
+
const output = {
|
|
32
|
+
summary: {
|
|
33
|
+
filesScanned: result.filesScanned,
|
|
34
|
+
patternsChecked: result.patternsChecked,
|
|
35
|
+
totalFindings: result.findings.length,
|
|
36
|
+
duration: result.duration,
|
|
37
|
+
timestamp: result.timestamp.toISOString(),
|
|
38
|
+
},
|
|
39
|
+
riskScore: {
|
|
40
|
+
score: result.riskScore.total,
|
|
41
|
+
level: result.riskScore.level,
|
|
42
|
+
owaspCompliance: result.riskScore.owaspCompliance,
|
|
43
|
+
counts: result.riskScore.counts,
|
|
44
|
+
},
|
|
45
|
+
findings: result.findings.map(serializeFinding),
|
|
46
|
+
};
|
|
47
|
+
return pretty ? JSON.stringify(output, null, 2) : JSON.stringify(output);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get findings summary as JSON object
|
|
51
|
+
*/
|
|
52
|
+
export function getFindingsSummary(result) {
|
|
53
|
+
const byCategory = {};
|
|
54
|
+
const bySeverity = {};
|
|
55
|
+
const byFile = {};
|
|
56
|
+
for (const finding of result.findings) {
|
|
57
|
+
byCategory[finding.pattern.category] = (byCategory[finding.pattern.category] || 0) + 1;
|
|
58
|
+
bySeverity[finding.pattern.severity] = (bySeverity[finding.pattern.severity] || 0) + 1;
|
|
59
|
+
byFile[finding.file] = (byFile[finding.file] || 0) + 1;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
total: result.findings.length,
|
|
63
|
+
byCategory,
|
|
64
|
+
bySeverity,
|
|
65
|
+
byFile,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Print JSON to console
|
|
70
|
+
*/
|
|
71
|
+
export function printJson(result, pretty = true) {
|
|
72
|
+
console.log(formatAsJson(result, pretty));
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/reporters/json.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Scanner
|
|
3
|
+
*
|
|
4
|
+
* Scans text content (prompts, configs, code) for security patterns.
|
|
5
|
+
*/
|
|
6
|
+
import type { DetectionPattern, Finding, ScanResult } from '../patterns/types.js';
|
|
7
|
+
export interface ScanOptions {
|
|
8
|
+
/** Patterns to use (defaults to all) */
|
|
9
|
+
patterns?: DetectionPattern[];
|
|
10
|
+
/** Minimum severity to report */
|
|
11
|
+
minSeverity?: 'critical' | 'high' | 'medium' | 'low';
|
|
12
|
+
/** File patterns to include */
|
|
13
|
+
include?: string[];
|
|
14
|
+
/** File patterns to exclude */
|
|
15
|
+
exclude?: string[];
|
|
16
|
+
}
|
|
17
|
+
declare const DEFAULT_INCLUDE: string[];
|
|
18
|
+
declare const DEFAULT_EXCLUDE: string[];
|
|
19
|
+
/**
|
|
20
|
+
* Scan a single file for security patterns
|
|
21
|
+
*/
|
|
22
|
+
export declare function scanFile(filePath: string, options?: ScanOptions): Promise<Finding[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Scan content string directly
|
|
25
|
+
*/
|
|
26
|
+
export declare function scanContent(content: string, source?: string, options?: ScanOptions): Finding[];
|
|
27
|
+
/**
|
|
28
|
+
* Scan a directory for security patterns
|
|
29
|
+
*/
|
|
30
|
+
export declare function scanDirectory(dirPath: string, options?: ScanOptions): Promise<ScanResult>;
|
|
31
|
+
/**
|
|
32
|
+
* Quick scan - only critical and high severity
|
|
33
|
+
*/
|
|
34
|
+
export declare function quickScan(dirPath: string): Promise<ScanResult>;
|
|
35
|
+
/**
|
|
36
|
+
* Full scan - all severities
|
|
37
|
+
*/
|
|
38
|
+
export declare function fullScan(dirPath: string): Promise<ScanResult>;
|
|
39
|
+
export { DEFAULT_INCLUDE, DEFAULT_EXCLUDE };
|
|
40
|
+
//# sourceMappingURL=content-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-scanner.d.ts","sourceRoot":"","sources":["../../src/scanner/content-scanner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAIlF,MAAM,WAAW,WAAW;IAC1B,wCAAwC;IACxC,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,iCAAiC;IACjC,WAAW,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACrD,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,QAAA,MAAM,eAAe,UAapB,CAAC;AAEF,QAAA,MAAM,eAAe,UAUpB,CAAC;AAEF;;GAEG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,OAAO,EAAE,CAAC,CAWpB;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAkB,EAC1B,OAAO,GAAE,WAAgB,GACxB,OAAO,EAAE,CAKX;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC,CAgCrB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAEpE;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAEnE;AAED,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Scanner
|
|
3
|
+
*
|
|
4
|
+
* Scans text content (prompts, configs, code) for security patterns.
|
|
5
|
+
*/
|
|
6
|
+
import { readFile } from 'fs/promises';
|
|
7
|
+
import { glob } from 'glob';
|
|
8
|
+
import { matchPatterns, createScanResult } from './engine.js';
|
|
9
|
+
import { ALL_PATTERNS, getPatternsMinSeverity } from '../patterns/index.js';
|
|
10
|
+
const DEFAULT_INCLUDE = [
|
|
11
|
+
'**/*.ts',
|
|
12
|
+
'**/*.tsx',
|
|
13
|
+
'**/*.js',
|
|
14
|
+
'**/*.jsx',
|
|
15
|
+
'**/*.py',
|
|
16
|
+
'**/*.md',
|
|
17
|
+
'**/*.txt',
|
|
18
|
+
'**/*.xml',
|
|
19
|
+
'**/*.yaml',
|
|
20
|
+
'**/*.yml',
|
|
21
|
+
'**/*.json',
|
|
22
|
+
'**/*.env*',
|
|
23
|
+
];
|
|
24
|
+
const DEFAULT_EXCLUDE = [
|
|
25
|
+
'**/node_modules/**',
|
|
26
|
+
'**/dist/**',
|
|
27
|
+
'**/build/**',
|
|
28
|
+
'**/.git/**',
|
|
29
|
+
'**/coverage/**',
|
|
30
|
+
'**/*.min.js',
|
|
31
|
+
'**/package-lock.json',
|
|
32
|
+
'**/pnpm-lock.yaml',
|
|
33
|
+
'**/yarn.lock',
|
|
34
|
+
];
|
|
35
|
+
/**
|
|
36
|
+
* Scan a single file for security patterns
|
|
37
|
+
*/
|
|
38
|
+
export async function scanFile(filePath, options = {}) {
|
|
39
|
+
const patterns = options.patterns ||
|
|
40
|
+
(options.minSeverity ? getPatternsMinSeverity(options.minSeverity) : ALL_PATTERNS);
|
|
41
|
+
try {
|
|
42
|
+
const content = await readFile(filePath, 'utf-8');
|
|
43
|
+
return matchPatterns(patterns, content, filePath);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
// File couldn't be read (binary, permission, etc.)
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Scan content string directly
|
|
52
|
+
*/
|
|
53
|
+
export function scanContent(content, source = '<input>', options = {}) {
|
|
54
|
+
const patterns = options.patterns ||
|
|
55
|
+
(options.minSeverity ? getPatternsMinSeverity(options.minSeverity) : ALL_PATTERNS);
|
|
56
|
+
return matchPatterns(patterns, content, source);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Scan a directory for security patterns
|
|
60
|
+
*/
|
|
61
|
+
export async function scanDirectory(dirPath, options = {}) {
|
|
62
|
+
const startTime = Date.now();
|
|
63
|
+
const patterns = options.patterns ||
|
|
64
|
+
(options.minSeverity ? getPatternsMinSeverity(options.minSeverity) : ALL_PATTERNS);
|
|
65
|
+
const include = options.include || DEFAULT_INCLUDE;
|
|
66
|
+
const exclude = options.exclude || DEFAULT_EXCLUDE;
|
|
67
|
+
// Find all matching files
|
|
68
|
+
const files = [];
|
|
69
|
+
for (const pattern of include) {
|
|
70
|
+
const matches = await glob(pattern, {
|
|
71
|
+
cwd: dirPath,
|
|
72
|
+
absolute: true,
|
|
73
|
+
ignore: exclude,
|
|
74
|
+
nodir: true,
|
|
75
|
+
});
|
|
76
|
+
files.push(...matches);
|
|
77
|
+
}
|
|
78
|
+
// Deduplicate files
|
|
79
|
+
const uniqueFiles = [...new Set(files)];
|
|
80
|
+
// Scan all files
|
|
81
|
+
const allFindings = [];
|
|
82
|
+
for (const file of uniqueFiles) {
|
|
83
|
+
const findings = await scanFile(file, { patterns });
|
|
84
|
+
allFindings.push(...findings);
|
|
85
|
+
}
|
|
86
|
+
return createScanResult(uniqueFiles.length, patterns.length, allFindings, startTime);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Quick scan - only critical and high severity
|
|
90
|
+
*/
|
|
91
|
+
export async function quickScan(dirPath) {
|
|
92
|
+
return scanDirectory(dirPath, { minSeverity: 'high' });
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Full scan - all severities
|
|
96
|
+
*/
|
|
97
|
+
export async function fullScan(dirPath) {
|
|
98
|
+
return scanDirectory(dirPath, { minSeverity: 'low' });
|
|
99
|
+
}
|
|
100
|
+
export { DEFAULT_INCLUDE, DEFAULT_EXCLUDE };
|
|
101
|
+
//# sourceMappingURL=content-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-scanner.js","sourceRoot":"","sources":["../../src/scanner/content-scanner.ts"],"names":[],"mappings":"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"}
|