@kairoaisec/cli 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/CHANGELOG.md +47 -0
- package/LICENSE +21 -0
- package/README.md +161 -0
- package/dist/api/client.d.ts +128 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +153 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +42 -0
- package/dist/api/index.js.map +1 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +72 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/auth/index.d.ts +3 -0
- package/dist/commands/auth/index.d.ts.map +1 -0
- package/dist/commands/auth/index.js +13 -0
- package/dist/commands/auth/index.js.map +1 -0
- package/dist/commands/auth/login.d.ts +3 -0
- package/dist/commands/auth/login.d.ts.map +1 -0
- package/dist/commands/auth/login.js +174 -0
- package/dist/commands/auth/login.js.map +1 -0
- package/dist/commands/auth/logout.d.ts +3 -0
- package/dist/commands/auth/logout.d.ts.map +1 -0
- package/dist/commands/auth/logout.js +56 -0
- package/dist/commands/auth/logout.js.map +1 -0
- package/dist/commands/auth/whoami.d.ts +3 -0
- package/dist/commands/auth/whoami.d.ts.map +1 -0
- package/dist/commands/auth/whoami.js +110 -0
- package/dist/commands/auth/whoami.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +102 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/project/create.d.ts +3 -0
- package/dist/commands/project/create.d.ts.map +1 -0
- package/dist/commands/project/create.js +146 -0
- package/dist/commands/project/create.js.map +1 -0
- package/dist/commands/project/index.d.ts +3 -0
- package/dist/commands/project/index.d.ts.map +1 -0
- package/dist/commands/project/index.js +14 -0
- package/dist/commands/project/index.js.map +1 -0
- package/dist/commands/project/list.d.ts +3 -0
- package/dist/commands/project/list.d.ts.map +1 -0
- package/dist/commands/project/list.js +116 -0
- package/dist/commands/project/list.js.map +1 -0
- package/dist/commands/project/select.d.ts +3 -0
- package/dist/commands/project/select.d.ts.map +1 -0
- package/dist/commands/project/select.js +147 -0
- package/dist/commands/project/select.js.map +1 -0
- package/dist/commands/scan.d.ts +3 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +401 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/config/index.d.ts +44 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +237 -0
- package/dist/config/index.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/file-discovery.d.ts +17 -0
- package/dist/lib/file-discovery.d.ts.map +1 -0
- package/dist/lib/file-discovery.js +218 -0
- package/dist/lib/file-discovery.js.map +1 -0
- package/dist/lib/patterns.d.ts +18 -0
- package/dist/lib/patterns.d.ts.map +1 -0
- package/dist/lib/patterns.js +187 -0
- package/dist/lib/patterns.js.map +1 -0
- package/dist/lib/sarif.d.ts +61 -0
- package/dist/lib/sarif.d.ts.map +1 -0
- package/dist/lib/sarif.js +169 -0
- package/dist/lib/sarif.js.map +1 -0
- package/dist/lib/scanner.d.ts +43 -0
- package/dist/lib/scanner.d.ts.map +1 -0
- package/dist/lib/scanner.js +163 -0
- package/dist/lib/scanner.js.map +1 -0
- package/dist/lib/slither.d.ts +112 -0
- package/dist/lib/slither.d.ts.map +1 -0
- package/dist/lib/slither.js +463 -0
- package/dist/lib/slither.js.map +1 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +44 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/spinner.d.ts +15 -0
- package/dist/utils/spinner.d.ts.map +1 -0
- package/dist/utils/spinner.js +55 -0
- package/dist/utils/spinner.js.map +1 -0
- package/dist/utils/validation.d.ts +12 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +79 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VULNERABILITY_PATTERNS = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Comprehensive vulnerability patterns ported from lib/scan-utils.ts
|
|
6
|
+
* These patterns detect common smart contract security issues
|
|
7
|
+
* Exactly 16 patterns from the main app scanner
|
|
8
|
+
*/
|
|
9
|
+
exports.VULNERABILITY_PATTERNS = [
|
|
10
|
+
{
|
|
11
|
+
id: 'reentrancy',
|
|
12
|
+
pattern: /\.call\{value:\s*[^}]+\}\s*\([^)]*\)/g,
|
|
13
|
+
severity: 'CRITICAL',
|
|
14
|
+
title: 'Potential Reentrancy Vulnerability',
|
|
15
|
+
description: 'External call with value transfer detected. Ensure state changes happen before external calls.',
|
|
16
|
+
recommendation: 'Apply the Checks-Effects-Interactions pattern. Use ReentrancyGuard modifier.',
|
|
17
|
+
category: 'Security',
|
|
18
|
+
cwe: 'CWE-841',
|
|
19
|
+
confidenceBase: 0.85,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: 'unchecked-call',
|
|
23
|
+
pattern: /\.call\{[^}]*\}\s*\([^)]*\)\s*;(?!\s*(require|if|assert|\(bool))/g,
|
|
24
|
+
severity: 'HIGH',
|
|
25
|
+
title: 'Unchecked External Call',
|
|
26
|
+
description: 'Return value of external call is not checked. Failed calls will not revert.',
|
|
27
|
+
recommendation: 'Always check return value of .call(). Use require(success) or handle failure explicitly.',
|
|
28
|
+
category: 'Security',
|
|
29
|
+
cwe: 'CWE-252',
|
|
30
|
+
confidenceBase: 0.9,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'tx-origin',
|
|
34
|
+
pattern: /tx\.origin/g,
|
|
35
|
+
severity: 'HIGH',
|
|
36
|
+
title: 'tx.origin Authentication',
|
|
37
|
+
description: 'Using tx.origin for authentication is vulnerable to phishing attacks.',
|
|
38
|
+
recommendation: 'Use msg.sender instead of tx.origin for authentication checks.',
|
|
39
|
+
category: 'Access Control',
|
|
40
|
+
cwe: 'CWE-284',
|
|
41
|
+
confidenceBase: 0.95,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'selfdestruct',
|
|
45
|
+
pattern: /selfdestruct\s*\(/g,
|
|
46
|
+
severity: 'CRITICAL',
|
|
47
|
+
title: 'Selfdestruct Usage',
|
|
48
|
+
description: 'selfdestruct can permanently destroy the contract and send funds to an address.',
|
|
49
|
+
recommendation: 'Add proper access control to selfdestruct calls. Consider if selfdestruct is necessary.',
|
|
50
|
+
category: 'Access Control',
|
|
51
|
+
cwe: 'CWE-284',
|
|
52
|
+
confidenceBase: 0.9,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 'delegatecall',
|
|
56
|
+
pattern: /\.delegatecall\s*\(/g,
|
|
57
|
+
severity: 'HIGH',
|
|
58
|
+
title: 'Delegatecall Usage',
|
|
59
|
+
description: 'delegatecall executes code in the context of the calling contract.',
|
|
60
|
+
recommendation: 'Only delegatecall to trusted, audited contracts. Avoid user-supplied addresses.',
|
|
61
|
+
category: 'Security',
|
|
62
|
+
cwe: 'CWE-829',
|
|
63
|
+
confidenceBase: 0.8,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 'timestamp-dependency',
|
|
67
|
+
pattern: /block\.timestamp|block\.number/g,
|
|
68
|
+
severity: 'MEDIUM',
|
|
69
|
+
title: 'Block Timestamp/Number Dependency',
|
|
70
|
+
description: 'Block values can be manipulated by miners within a certain range.',
|
|
71
|
+
recommendation: 'Avoid using block values for randomness or critical time windows.',
|
|
72
|
+
category: 'Security',
|
|
73
|
+
cwe: 'CWE-330',
|
|
74
|
+
confidenceBase: 0.7,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: 'integer-overflow',
|
|
78
|
+
pattern: /(?<!\+\+|\-\-)\s*(\+|\-|\*)\s*(?!\+|\-)(?!.*SafeMath)/g,
|
|
79
|
+
severity: 'MEDIUM',
|
|
80
|
+
title: 'Potential Integer Overflow/Underflow',
|
|
81
|
+
description: 'Arithmetic operation without SafeMath (for Solidity < 0.8.0).',
|
|
82
|
+
recommendation: 'Use Solidity 0.8+ or SafeMath library for arithmetic operations.',
|
|
83
|
+
category: 'Security',
|
|
84
|
+
cwe: 'CWE-190',
|
|
85
|
+
confidenceBase: 0.6,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: 'floating-pragma',
|
|
89
|
+
pattern: /pragma\s+solidity\s*\^/g,
|
|
90
|
+
severity: 'LOW',
|
|
91
|
+
title: 'Floating Pragma',
|
|
92
|
+
description: 'Contract may be compiled with different compiler versions.',
|
|
93
|
+
recommendation: 'Lock pragma to specific version (e.g., pragma solidity 0.8.20).',
|
|
94
|
+
category: 'Best Practices',
|
|
95
|
+
cwe: 'CWE-1103',
|
|
96
|
+
confidenceBase: 0.95,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 'public-burn',
|
|
100
|
+
pattern: /function\s+burn\s*\([^)]*\)\s*(external|public)/g,
|
|
101
|
+
severity: 'MEDIUM',
|
|
102
|
+
title: 'Public Burn Function',
|
|
103
|
+
description: 'Publicly accessible burn function could be exploited without proper authorization.',
|
|
104
|
+
recommendation: 'Ensure burn functions have proper authorization checks.',
|
|
105
|
+
category: 'Token Security',
|
|
106
|
+
cwe: 'CWE-284',
|
|
107
|
+
confidenceBase: 0.7,
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
id: 'msg-value-loop',
|
|
111
|
+
pattern: /for\s*\([^)]*\)\s*\{[^}]*msg\.value/g,
|
|
112
|
+
severity: 'HIGH',
|
|
113
|
+
title: 'msg.value in Loop',
|
|
114
|
+
description: 'Using msg.value inside a loop can lead to unexpected behavior.',
|
|
115
|
+
recommendation: 'Calculate total expected value before loop and validate once.',
|
|
116
|
+
category: 'Security',
|
|
117
|
+
cwe: 'CWE-670',
|
|
118
|
+
confidenceBase: 0.88,
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: 'gas-griefing',
|
|
122
|
+
pattern: /\.call\{[^}]*\}\s*\([^)]*\)\s*;/g,
|
|
123
|
+
severity: 'HIGH',
|
|
124
|
+
title: 'Potential Gas Griefing Vulnerability',
|
|
125
|
+
description: 'External call may consume excessive gas if recipient is malicious contract with expensive fallback.',
|
|
126
|
+
recommendation: 'Set explicit gas limit for external calls: .call{gas: 50000, value: amount}("")',
|
|
127
|
+
category: 'Security',
|
|
128
|
+
cwe: 'CWE-400',
|
|
129
|
+
confidenceBase: 0.75,
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: 'unbounded-loop-external',
|
|
133
|
+
pattern: /for\s*\([^)]*\)\s*\{[^}]*(\.call|\.send|\.transfer)/g,
|
|
134
|
+
severity: 'CRITICAL',
|
|
135
|
+
title: 'Unbounded Loop with External Calls',
|
|
136
|
+
description: 'External calls in unbounded loops can cause out-of-gas errors, blocking contract functionality.',
|
|
137
|
+
recommendation: 'Use pull-over-push pattern or limit loop iterations.',
|
|
138
|
+
category: 'Security',
|
|
139
|
+
cwe: 'CWE-400',
|
|
140
|
+
confidenceBase: 0.9,
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: 'return-bomb',
|
|
144
|
+
pattern: /\(bool\s+\w+,\s*bytes\s+memory\s+\w+\)\s*=\s*\w+\.call/g,
|
|
145
|
+
severity: 'MEDIUM',
|
|
146
|
+
title: 'Potential Return Data Bomb',
|
|
147
|
+
description: 'Unbounded return data from external call can consume excessive memory gas.',
|
|
148
|
+
recommendation: 'Ignore return data if not needed: (bool success, ) = target.call(...)',
|
|
149
|
+
category: 'Security',
|
|
150
|
+
cwe: 'CWE-400',
|
|
151
|
+
confidenceBase: 0.7,
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
id: 'signature-no-nonce',
|
|
155
|
+
pattern: /ecrecover|ECDSA\.recover/g,
|
|
156
|
+
severity: 'CRITICAL',
|
|
157
|
+
title: 'Signature Verification Without Nonce',
|
|
158
|
+
description: 'Signature can be replayed multiple times without nonce tracking.',
|
|
159
|
+
recommendation: 'Include and track nonce in signed message. Mark nonces as used after verification.',
|
|
160
|
+
category: 'Access Control',
|
|
161
|
+
cwe: 'CWE-294',
|
|
162
|
+
confidenceBase: 0.6,
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: 'signature-no-chainid',
|
|
166
|
+
pattern: /ecrecover|ECDSA\.recover/g,
|
|
167
|
+
severity: 'HIGH',
|
|
168
|
+
title: 'Signature Missing Chain ID',
|
|
169
|
+
description: 'Signature valid on one chain can be replayed on another chain.',
|
|
170
|
+
recommendation: 'Include block.chainid in signed message hash (EIP-712 domain separator).',
|
|
171
|
+
category: 'Access Control',
|
|
172
|
+
cwe: 'CWE-294',
|
|
173
|
+
confidenceBase: 0.65,
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
id: 'signature-no-deadline',
|
|
177
|
+
pattern: /ecrecover|ECDSA\.recover/g,
|
|
178
|
+
severity: 'MEDIUM',
|
|
179
|
+
title: 'Signature Without Expiration',
|
|
180
|
+
description: 'Signatures without deadline can be held and replayed indefinitely.',
|
|
181
|
+
recommendation: 'Include deadline timestamp in signed message and validate before processing.',
|
|
182
|
+
category: 'Access Control',
|
|
183
|
+
cwe: 'CWE-613',
|
|
184
|
+
confidenceBase: 0.7,
|
|
185
|
+
},
|
|
186
|
+
];
|
|
187
|
+
//# sourceMappingURL=patterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../src/lib/patterns.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Finding } from './scanner.js';
|
|
2
|
+
interface SarifReport {
|
|
3
|
+
version: '2.1.0';
|
|
4
|
+
$schema: string;
|
|
5
|
+
runs: SarifRun[];
|
|
6
|
+
}
|
|
7
|
+
interface SarifRun {
|
|
8
|
+
tool: {
|
|
9
|
+
driver: {
|
|
10
|
+
name: string;
|
|
11
|
+
version: string;
|
|
12
|
+
informationUri: string;
|
|
13
|
+
rules: SarifRule[];
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
results: SarifResult[];
|
|
17
|
+
}
|
|
18
|
+
interface SarifRule {
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
shortDescription: {
|
|
22
|
+
text: string;
|
|
23
|
+
};
|
|
24
|
+
fullDescription: {
|
|
25
|
+
text: string;
|
|
26
|
+
};
|
|
27
|
+
help: {
|
|
28
|
+
text: string;
|
|
29
|
+
markdown: string;
|
|
30
|
+
};
|
|
31
|
+
properties: {
|
|
32
|
+
tags: string[];
|
|
33
|
+
precision: string;
|
|
34
|
+
'security-severity': string;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
interface SarifResult {
|
|
38
|
+
ruleId: string;
|
|
39
|
+
level: 'error' | 'warning' | 'note';
|
|
40
|
+
message: {
|
|
41
|
+
text: string;
|
|
42
|
+
};
|
|
43
|
+
locations: Array<{
|
|
44
|
+
physicalLocation: {
|
|
45
|
+
artifactLocation: {
|
|
46
|
+
uri: string;
|
|
47
|
+
};
|
|
48
|
+
region: {
|
|
49
|
+
startLine: number;
|
|
50
|
+
endLine: number;
|
|
51
|
+
snippet: {
|
|
52
|
+
text: string;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
}>;
|
|
57
|
+
}
|
|
58
|
+
export declare function generateSarifReport(findings: Finding[], projectRoot: string): SarifReport;
|
|
59
|
+
export declare function writeSarifReport(report: SarifReport, outputPath: string): void;
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=sarif.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sarif.d.ts","sourceRoot":"","sources":["../../src/lib/sarif.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,UAAU,WAAW;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,QAAQ,EAAE,CAAC;CAClB;AAED,UAAU,QAAQ;IAChB,IAAI,EAAE;QACJ,MAAM,EAAE;YACN,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,MAAM,CAAC;YAChB,cAAc,EAAE,MAAM,CAAC;YACvB,KAAK,EAAE,SAAS,EAAE,CAAC;SACpB,CAAC;KACH,CAAC;IACF,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAED,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE;QAChB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,eAAe,EAAE;QACf,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;CACH;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACpC,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,SAAS,EAAE,KAAK,CAAC;QACf,gBAAgB,EAAE;YAChB,gBAAgB,EAAE;gBAChB,GAAG,EAAE,MAAM,CAAC;aACb,CAAC;YACF,MAAM,EAAE;gBACN,SAAS,EAAE,MAAM,CAAC;gBAClB,OAAO,EAAE,MAAM,CAAC;gBAChB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAM,CAAC;iBACd,CAAC;aACH,CAAC;SACH,CAAC;KACH,CAAC,CAAC;CACJ;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,WAAW,CAyFzF;AAgDD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAG9E"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.generateSarifReport = generateSarifReport;
|
|
37
|
+
exports.writeSarifReport = writeSarifReport;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
function generateSarifReport(findings, projectRoot) {
|
|
41
|
+
// Group findings by pattern_id to create rules
|
|
42
|
+
const ruleMap = new Map();
|
|
43
|
+
for (const finding of findings) {
|
|
44
|
+
const ruleId = finding.pattern_id;
|
|
45
|
+
if (!ruleMap.has(ruleId)) {
|
|
46
|
+
ruleMap.set(ruleId, []);
|
|
47
|
+
}
|
|
48
|
+
ruleMap.get(ruleId).push(finding);
|
|
49
|
+
}
|
|
50
|
+
// Create SARIF rules from unique patterns
|
|
51
|
+
const rules = Array.from(ruleMap.entries()).map(([ruleId, findings]) => {
|
|
52
|
+
const firstFinding = findings[0];
|
|
53
|
+
return {
|
|
54
|
+
id: ruleId,
|
|
55
|
+
name: firstFinding.title,
|
|
56
|
+
shortDescription: {
|
|
57
|
+
text: firstFinding.title,
|
|
58
|
+
},
|
|
59
|
+
fullDescription: {
|
|
60
|
+
text: firstFinding.description,
|
|
61
|
+
},
|
|
62
|
+
help: {
|
|
63
|
+
text: firstFinding.recommendation,
|
|
64
|
+
markdown: `## ${firstFinding.title}\n\n${firstFinding.description}${firstFinding.recommendation
|
|
65
|
+
? `\n\n### Recommendation\n\n${firstFinding.recommendation}`
|
|
66
|
+
: ''}${firstFinding.cwe ? `\n\n### CWE\n\n${firstFinding.cwe}` : ''}`,
|
|
67
|
+
},
|
|
68
|
+
properties: {
|
|
69
|
+
tags: ['security', 'solidity', firstFinding.category.toLowerCase()],
|
|
70
|
+
precision: firstFinding.confidence * 100 >= 80
|
|
71
|
+
? 'high'
|
|
72
|
+
: firstFinding.confidence * 100 >= 60
|
|
73
|
+
? 'medium'
|
|
74
|
+
: 'low',
|
|
75
|
+
'security-severity': getSeverityScore(firstFinding.severity),
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
// Create SARIF results from findings
|
|
80
|
+
const results = findings.map((finding) => ({
|
|
81
|
+
ruleId: finding.pattern_id,
|
|
82
|
+
level: getSarifLevel(finding.severity),
|
|
83
|
+
message: {
|
|
84
|
+
text: finding.description,
|
|
85
|
+
},
|
|
86
|
+
locations: [
|
|
87
|
+
{
|
|
88
|
+
physicalLocation: {
|
|
89
|
+
artifactLocation: {
|
|
90
|
+
uri: path.relative(projectRoot, finding.file_path),
|
|
91
|
+
},
|
|
92
|
+
region: {
|
|
93
|
+
startLine: finding.line_start,
|
|
94
|
+
endLine: finding.line_end,
|
|
95
|
+
snippet: {
|
|
96
|
+
text: finding.code_snippet ||
|
|
97
|
+
getCodeSnippet(finding.file_path, finding.line_start, finding.line_end),
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
}));
|
|
104
|
+
return {
|
|
105
|
+
version: '2.1.0',
|
|
106
|
+
$schema: 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json',
|
|
107
|
+
runs: [
|
|
108
|
+
{
|
|
109
|
+
tool: {
|
|
110
|
+
driver: {
|
|
111
|
+
name: 'Kairo Security Scanner',
|
|
112
|
+
version: '1.0.0',
|
|
113
|
+
informationUri: 'https://kairoaisec.com',
|
|
114
|
+
rules,
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
results,
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function getSarifLevel(severity) {
|
|
123
|
+
switch (severity.toUpperCase()) {
|
|
124
|
+
case 'CRITICAL':
|
|
125
|
+
case 'HIGH':
|
|
126
|
+
return 'error';
|
|
127
|
+
case 'MEDIUM':
|
|
128
|
+
return 'warning';
|
|
129
|
+
case 'LOW':
|
|
130
|
+
case 'INFO':
|
|
131
|
+
default:
|
|
132
|
+
return 'note';
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function getSeverityScore(severity) {
|
|
136
|
+
switch (severity.toUpperCase()) {
|
|
137
|
+
case 'CRITICAL':
|
|
138
|
+
return '9.0';
|
|
139
|
+
case 'HIGH':
|
|
140
|
+
return '7.0';
|
|
141
|
+
case 'MEDIUM':
|
|
142
|
+
return '4.0';
|
|
143
|
+
case 'LOW':
|
|
144
|
+
return '2.0';
|
|
145
|
+
case 'INFO':
|
|
146
|
+
default:
|
|
147
|
+
return '0.0';
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function getCodeSnippet(filePath, lineStart, lineEnd) {
|
|
151
|
+
try {
|
|
152
|
+
if (!lineStart)
|
|
153
|
+
return '';
|
|
154
|
+
const fileContent = fs.readFileSync(filePath, 'utf-8');
|
|
155
|
+
const lines = fileContent.split('\n');
|
|
156
|
+
const start = Math.max(0, lineStart - 1);
|
|
157
|
+
const end = Math.min(lines.length, lineEnd || lineStart);
|
|
158
|
+
return lines.slice(start, end).join('\n');
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
// If we can't read the file, return empty snippet
|
|
162
|
+
return '';
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function writeSarifReport(report, outputPath) {
|
|
166
|
+
const json = JSON.stringify(report, null, 2);
|
|
167
|
+
fs.writeFileSync(outputPath, json, 'utf-8');
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=sarif.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sarif.js","sourceRoot":"","sources":["../../src/lib/sarif.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface Finding {
|
|
2
|
+
id: string;
|
|
3
|
+
severity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW';
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
file_path: string;
|
|
7
|
+
line_start: number;
|
|
8
|
+
line_end: number;
|
|
9
|
+
code_snippet: string;
|
|
10
|
+
recommendation: string;
|
|
11
|
+
confidence: number;
|
|
12
|
+
cwe?: string;
|
|
13
|
+
pattern_id: string;
|
|
14
|
+
category: string;
|
|
15
|
+
fingerprint: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Scan a single file for vulnerability patterns
|
|
19
|
+
*/
|
|
20
|
+
export declare function scanFile(filePath: string): Promise<Finding[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Scan file content for vulnerability patterns with context-aware detection
|
|
23
|
+
*/
|
|
24
|
+
export declare function scanFileContent(content: string, filePath: string): Finding[];
|
|
25
|
+
/**
|
|
26
|
+
* Aggregate findings by severity
|
|
27
|
+
*/
|
|
28
|
+
export declare function aggregateFindings(findings: Finding[]): {
|
|
29
|
+
CRITICAL: number;
|
|
30
|
+
HIGH: number;
|
|
31
|
+
MEDIUM: number;
|
|
32
|
+
LOW: number;
|
|
33
|
+
total: number;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Sort findings by severity and confidence
|
|
37
|
+
*/
|
|
38
|
+
export declare function sortFindings(findings: Finding[]): Finding[];
|
|
39
|
+
/**
|
|
40
|
+
* Filter findings by severity level
|
|
41
|
+
*/
|
|
42
|
+
export declare function filterBySeverity(findings: Finding[], minSeverity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW'): Finding[];
|
|
43
|
+
//# sourceMappingURL=scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/lib/scanner.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAQnE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,CAmG5E;AAsBD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAcA;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAU3D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,OAAO,EAAE,EACnB,WAAW,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAClD,OAAO,EAAE,CAKX"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.scanFile = scanFile;
|
|
4
|
+
exports.scanFileContent = scanFileContent;
|
|
5
|
+
exports.aggregateFindings = aggregateFindings;
|
|
6
|
+
exports.sortFindings = sortFindings;
|
|
7
|
+
exports.filterBySeverity = filterBySeverity;
|
|
8
|
+
const promises_1 = require("fs/promises");
|
|
9
|
+
const crypto_1 = require("crypto");
|
|
10
|
+
const patterns_js_1 = require("./patterns.js");
|
|
11
|
+
/**
|
|
12
|
+
* Scan a single file for vulnerability patterns
|
|
13
|
+
*/
|
|
14
|
+
async function scanFile(filePath) {
|
|
15
|
+
try {
|
|
16
|
+
const content = await (0, promises_1.readFile)(filePath, 'utf8');
|
|
17
|
+
return scanFileContent(content, filePath);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
console.error(`Error reading file ${filePath}:`, error);
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Scan file content for vulnerability patterns with context-aware detection
|
|
26
|
+
*/
|
|
27
|
+
function scanFileContent(content, filePath) {
|
|
28
|
+
const findings = [];
|
|
29
|
+
const lines = content.split('\n');
|
|
30
|
+
for (const pattern of patterns_js_1.VULNERABILITY_PATTERNS) {
|
|
31
|
+
const regex = new RegExp(pattern.pattern.source, pattern.pattern.flags);
|
|
32
|
+
let match;
|
|
33
|
+
while ((match = regex.exec(content)) !== null) {
|
|
34
|
+
const beforeMatch = content.substring(0, match.index);
|
|
35
|
+
const lineNumber = beforeMatch.split('\n').length;
|
|
36
|
+
// Check if match is in a comment
|
|
37
|
+
const line = lines[lineNumber - 1] || '';
|
|
38
|
+
const isComment = /^\s*(\/\/|\/\*|\*)/.test(line.trim());
|
|
39
|
+
// Adjust confidence based on context
|
|
40
|
+
let confidence = pattern.confidenceBase;
|
|
41
|
+
if (isComment) {
|
|
42
|
+
confidence *= 0.2; // Reduce confidence for commented code
|
|
43
|
+
}
|
|
44
|
+
// Skip low confidence matches
|
|
45
|
+
if (confidence < 0.3)
|
|
46
|
+
continue;
|
|
47
|
+
// Get code snippet for context (3 lines before and after)
|
|
48
|
+
const snippetStart = Math.max(0, lineNumber - 2);
|
|
49
|
+
const snippetEnd = Math.min(lines.length, lineNumber + 2);
|
|
50
|
+
const codeSnippet = lines.slice(snippetStart, snippetEnd).join('\n');
|
|
51
|
+
// Generate fingerprint for deduplication
|
|
52
|
+
const fingerprint = generateFindingFingerprint(filePath, pattern.id, lineNumber, codeSnippet);
|
|
53
|
+
findings.push({
|
|
54
|
+
id: (0, crypto_1.randomUUID)(),
|
|
55
|
+
severity: pattern.severity,
|
|
56
|
+
title: pattern.title,
|
|
57
|
+
description: pattern.description,
|
|
58
|
+
file_path: filePath,
|
|
59
|
+
line_start: lineNumber,
|
|
60
|
+
line_end: lineNumber,
|
|
61
|
+
code_snippet: codeSnippet,
|
|
62
|
+
recommendation: pattern.recommendation,
|
|
63
|
+
confidence: Math.round(confidence * 100) / 100,
|
|
64
|
+
cwe: pattern.cwe,
|
|
65
|
+
pattern_id: pattern.id,
|
|
66
|
+
category: pattern.category,
|
|
67
|
+
fingerprint,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Context-aware detection for signature patterns
|
|
72
|
+
const signatureFindings = findings.filter((f) => f.pattern_id.startsWith('signature-'));
|
|
73
|
+
for (const finding of signatureFindings) {
|
|
74
|
+
// Check if nonce/chainId/deadline is used within 20 lines
|
|
75
|
+
const startLine = Math.max(0, finding.line_start - 10);
|
|
76
|
+
const endLine = Math.min(lines.length, finding.line_start + 10);
|
|
77
|
+
const context = lines.slice(startLine, endLine).join('\n');
|
|
78
|
+
if (finding.pattern_id === 'signature-no-nonce' && /nonce|usedNonces|_nonces/.test(context)) {
|
|
79
|
+
finding.confidence *= 0.3; // Likely false positive
|
|
80
|
+
}
|
|
81
|
+
if (finding.pattern_id === 'signature-no-chainid' &&
|
|
82
|
+
/chainId|block\.chainid|domainSeparator/.test(context)) {
|
|
83
|
+
finding.confidence *= 0.3;
|
|
84
|
+
}
|
|
85
|
+
if (finding.pattern_id === 'signature-no-deadline' && /deadline|expiry|validUntil/.test(context)) {
|
|
86
|
+
finding.confidence *= 0.3;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Context-aware detection for gas griefing patterns
|
|
90
|
+
const gasFindings = findings.filter((f) => f.pattern_id === 'gas-griefing');
|
|
91
|
+
for (const finding of gasFindings) {
|
|
92
|
+
const startLine = Math.max(0, finding.line_start - 5);
|
|
93
|
+
const endLine = Math.min(lines.length, finding.line_start + 5);
|
|
94
|
+
const context = lines.slice(startLine, endLine).join('\n');
|
|
95
|
+
// Reduce confidence if gas limit is already set
|
|
96
|
+
if (/\.call\{[^}]*gas:\s*\d+/.test(context)) {
|
|
97
|
+
finding.confidence *= 0.3;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Filter out low confidence findings after context analysis
|
|
101
|
+
const filteredFindings = findings.filter(f => f.confidence >= 0.3);
|
|
102
|
+
// Deduplicate findings by fingerprint
|
|
103
|
+
const seen = new Set();
|
|
104
|
+
const uniqueFindings = filteredFindings.filter((f) => {
|
|
105
|
+
if (seen.has(f.fingerprint))
|
|
106
|
+
return false;
|
|
107
|
+
seen.add(f.fingerprint);
|
|
108
|
+
return true;
|
|
109
|
+
});
|
|
110
|
+
return uniqueFindings;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Generate a unique fingerprint for a finding to enable deduplication
|
|
114
|
+
*/
|
|
115
|
+
function generateFindingFingerprint(filePath, patternId, lineNumber, codeSnippet) {
|
|
116
|
+
// Create a simple hash of the key components
|
|
117
|
+
const content = `${filePath}:${patternId}:${lineNumber}:${codeSnippet.trim()}`;
|
|
118
|
+
let hash = 0;
|
|
119
|
+
for (let i = 0; i < content.length; i++) {
|
|
120
|
+
const char = content.charCodeAt(i);
|
|
121
|
+
hash = ((hash << 5) - hash) + char;
|
|
122
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
123
|
+
}
|
|
124
|
+
return Math.abs(hash).toString(36);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Aggregate findings by severity
|
|
128
|
+
*/
|
|
129
|
+
function aggregateFindings(findings) {
|
|
130
|
+
const counts = {
|
|
131
|
+
CRITICAL: 0,
|
|
132
|
+
HIGH: 0,
|
|
133
|
+
MEDIUM: 0,
|
|
134
|
+
LOW: 0,
|
|
135
|
+
total: findings.length,
|
|
136
|
+
};
|
|
137
|
+
for (const finding of findings) {
|
|
138
|
+
counts[finding.severity]++;
|
|
139
|
+
}
|
|
140
|
+
return counts;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Sort findings by severity and confidence
|
|
144
|
+
*/
|
|
145
|
+
function sortFindings(findings) {
|
|
146
|
+
const severityOrder = { CRITICAL: 0, HIGH: 1, MEDIUM: 2, LOW: 3 };
|
|
147
|
+
return findings.sort((a, b) => {
|
|
148
|
+
const severityDiff = severityOrder[a.severity] - severityOrder[b.severity];
|
|
149
|
+
if (severityDiff !== 0)
|
|
150
|
+
return severityDiff;
|
|
151
|
+
// If same severity, sort by confidence (higher first)
|
|
152
|
+
return b.confidence - a.confidence;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Filter findings by severity level
|
|
157
|
+
*/
|
|
158
|
+
function filterBySeverity(findings, minSeverity) {
|
|
159
|
+
const severityOrder = { CRITICAL: 0, HIGH: 1, MEDIUM: 2, LOW: 3 };
|
|
160
|
+
const minLevel = severityOrder[minSeverity];
|
|
161
|
+
return findings.filter(finding => severityOrder[finding.severity] <= minLevel);
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/lib/scanner.ts"],"names":[],"mappings":"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"}
|