@surfinguard/core-engine 0.1.0 → 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/dist/analyzers/agent-comm.d.ts +22 -0
- package/dist/analyzers/agent-comm.d.ts.map +1 -0
- package/dist/analyzers/agent-comm.js +79 -0
- package/dist/analyzers/agent-comm.js.map +1 -0
- package/dist/analyzers/api-call.d.ts +21 -0
- package/dist/analyzers/api-call.d.ts.map +1 -0
- package/dist/analyzers/api-call.js +134 -0
- package/dist/analyzers/api-call.js.map +1 -0
- package/dist/analyzers/auth.d.ts +22 -0
- package/dist/analyzers/auth.d.ts.map +1 -0
- package/dist/analyzers/auth.js +97 -0
- package/dist/analyzers/auth.js.map +1 -0
- package/dist/analyzers/code.d.ts +32 -0
- package/dist/analyzers/code.d.ts.map +1 -0
- package/dist/analyzers/code.js +310 -0
- package/dist/analyzers/code.js.map +1 -0
- package/dist/analyzers/command.d.ts.map +1 -1
- package/dist/analyzers/command.js +91 -39
- package/dist/analyzers/command.js.map +1 -1
- package/dist/analyzers/data-pipeline.d.ts +23 -0
- package/dist/analyzers/data-pipeline.d.ts.map +1 -0
- package/dist/analyzers/data-pipeline.js +86 -0
- package/dist/analyzers/data-pipeline.js.map +1 -0
- package/dist/analyzers/document.d.ts +22 -0
- package/dist/analyzers/document.d.ts.map +1 -0
- package/dist/analyzers/document.js +77 -0
- package/dist/analyzers/document.js.map +1 -0
- package/dist/analyzers/file-read.d.ts.map +1 -1
- package/dist/analyzers/file-read.js +12 -3
- package/dist/analyzers/file-read.js.map +1 -1
- package/dist/analyzers/file-write.d.ts.map +1 -1
- package/dist/analyzers/file-write.js +12 -3
- package/dist/analyzers/file-write.js.map +1 -1
- package/dist/analyzers/git.d.ts +25 -0
- package/dist/analyzers/git.d.ts.map +1 -0
- package/dist/analyzers/git.js +126 -0
- package/dist/analyzers/git.js.map +1 -0
- package/dist/analyzers/index.d.ts +3 -0
- package/dist/analyzers/index.d.ts.map +1 -1
- package/dist/analyzers/index.js +3 -0
- package/dist/analyzers/index.js.map +1 -1
- package/dist/analyzers/infra.d.ts +30 -0
- package/dist/analyzers/infra.d.ts.map +1 -0
- package/dist/analyzers/infra.js +134 -0
- package/dist/analyzers/infra.js.map +1 -0
- package/dist/analyzers/iot.d.ts +22 -0
- package/dist/analyzers/iot.d.ts.map +1 -0
- package/dist/analyzers/iot.js +78 -0
- package/dist/analyzers/iot.js.map +1 -0
- package/dist/analyzers/message.d.ts +22 -0
- package/dist/analyzers/message.d.ts.map +1 -0
- package/dist/analyzers/message.js +106 -0
- package/dist/analyzers/message.js.map +1 -0
- package/dist/analyzers/query.d.ts +23 -0
- package/dist/analyzers/query.d.ts.map +1 -0
- package/dist/analyzers/query.js +183 -0
- package/dist/analyzers/query.js.map +1 -0
- package/dist/analyzers/text.d.ts.map +1 -1
- package/dist/analyzers/text.js +20 -3
- package/dist/analyzers/text.js.map +1 -1
- package/dist/analyzers/transaction.d.ts +23 -0
- package/dist/analyzers/transaction.d.ts.map +1 -0
- package/dist/analyzers/transaction.js +100 -0
- package/dist/analyzers/transaction.js.map +1 -0
- package/dist/analyzers/ui-action.d.ts +23 -0
- package/dist/analyzers/ui-action.d.ts.map +1 -0
- package/dist/analyzers/ui-action.js +92 -0
- package/dist/analyzers/ui-action.js.map +1 -0
- package/dist/analyzers/url.d.ts.map +1 -1
- package/dist/analyzers/url.js +6 -2
- package/dist/analyzers/url.js.map +1 -1
- package/dist/classifier.d.ts.map +1 -1
- package/dist/classifier.js +20 -1
- package/dist/classifier.js.map +1 -1
- package/dist/context.d.ts +6 -4
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +34 -5
- package/dist/context.js.map +1 -1
- package/dist/engine.d.ts +72 -3
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +313 -9
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/patterns.d.ts +15 -1
- package/dist/patterns.d.ts.map +1 -1
- package/dist/patterns.js +70 -53
- package/dist/patterns.js.map +1 -1
- package/dist/policy-engine.d.ts +44 -0
- package/dist/policy-engine.d.ts.map +1 -0
- package/dist/policy-engine.js +225 -0
- package/dist/policy-engine.js.map +1 -0
- package/dist/session-tracker.d.ts +50 -0
- package/dist/session-tracker.d.ts.map +1 -0
- package/dist/session-tracker.js +286 -0
- package/dist/session-tracker.js.map +1 -0
- package/package.json +15 -12
- package/patterns/agent-comm.json +97 -0
- package/patterns/api-call.json +175 -0
- package/patterns/auth.json +116 -0
- package/patterns/chains.json +171 -0
- package/patterns/code.json +204 -0
- package/patterns/data-pipeline.json +116 -0
- package/patterns/document.json +110 -0
- package/patterns/git.json +118 -0
- package/patterns/infra.json +207 -0
- package/patterns/iot.json +105 -0
- package/patterns/message.json +122 -0
- package/patterns/query.json +134 -0
- package/patterns/transaction.json +120 -0
- package/patterns/ui-action.json +137 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Analyzer — detects malicious code generation patterns.
|
|
3
|
+
*
|
|
4
|
+
* Detects 8 threat patterns (G01-G08) mapped to 5 risk primitives.
|
|
5
|
+
* Input: value = code string, metadata.language optional.
|
|
6
|
+
*/
|
|
7
|
+
export class CodeAnalyzer {
|
|
8
|
+
actionType = 'code_eval';
|
|
9
|
+
safePatterns;
|
|
10
|
+
backdoorPatterns;
|
|
11
|
+
backdoorRegexes;
|
|
12
|
+
vulnerabilityPatterns;
|
|
13
|
+
vulnerabilityRegexes;
|
|
14
|
+
dependencyConfusion;
|
|
15
|
+
obfuscationPatterns;
|
|
16
|
+
obfuscationRegexes;
|
|
17
|
+
phoneHomeRegexes;
|
|
18
|
+
insecureDefaults;
|
|
19
|
+
insecureRegexes;
|
|
20
|
+
logicBombRegexes;
|
|
21
|
+
cryptoRegexes;
|
|
22
|
+
constructor(patterns) {
|
|
23
|
+
this.safePatterns = patterns.safePatterns.map((p) => p.toLowerCase());
|
|
24
|
+
this.dependencyConfusion = new Set(patterns.dependencyConfusion.map((p) => p.toLowerCase()));
|
|
25
|
+
// Separate regex patterns from string patterns
|
|
26
|
+
// Use 'is' (case-insensitive + dotAll) for multi-line code matching
|
|
27
|
+
this.backdoorPatterns = [];
|
|
28
|
+
this.backdoorRegexes = [];
|
|
29
|
+
for (const p of patterns.backdoorPatterns) {
|
|
30
|
+
if (this.isRegexPattern(p)) {
|
|
31
|
+
try {
|
|
32
|
+
this.backdoorRegexes.push(new RegExp(p, 'is'));
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
this.backdoorPatterns.push(p.toLowerCase());
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
this.backdoorPatterns.push(p.toLowerCase());
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
this.vulnerabilityPatterns = [];
|
|
43
|
+
this.vulnerabilityRegexes = [];
|
|
44
|
+
for (const p of patterns.vulnerabilityPatterns) {
|
|
45
|
+
if (this.isRegexPattern(p)) {
|
|
46
|
+
try {
|
|
47
|
+
this.vulnerabilityRegexes.push(new RegExp(p, 'is'));
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
this.vulnerabilityPatterns.push(p.toLowerCase());
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
this.vulnerabilityPatterns.push(p.toLowerCase());
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
this.obfuscationPatterns = [];
|
|
58
|
+
this.obfuscationRegexes = [];
|
|
59
|
+
for (const p of patterns.obfuscationPatterns) {
|
|
60
|
+
if (this.isRegexPattern(p)) {
|
|
61
|
+
try {
|
|
62
|
+
this.obfuscationRegexes.push(new RegExp(p, 'is'));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
this.obfuscationPatterns.push(p.toLowerCase());
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
this.obfuscationPatterns.push(p.toLowerCase());
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
this.phoneHomeRegexes = [];
|
|
73
|
+
for (const p of patterns.phoneHomePatterns) {
|
|
74
|
+
try {
|
|
75
|
+
this.phoneHomeRegexes.push(new RegExp(p, 'is'));
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
/* skip */
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
this.insecureDefaults = [];
|
|
82
|
+
this.insecureRegexes = [];
|
|
83
|
+
for (const p of patterns.insecureDefaults) {
|
|
84
|
+
if (this.isRegexPattern(p)) {
|
|
85
|
+
try {
|
|
86
|
+
this.insecureRegexes.push(new RegExp(p, 'is'));
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
this.insecureDefaults.push(p.toLowerCase());
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
this.insecureDefaults.push(p.toLowerCase());
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
this.logicBombRegexes = [];
|
|
97
|
+
for (const p of patterns.logicBombPatterns) {
|
|
98
|
+
try {
|
|
99
|
+
this.logicBombRegexes.push(new RegExp(p, 'is'));
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
/* skip */
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
this.cryptoRegexes = [];
|
|
106
|
+
for (const p of patterns.cryptoReplacement) {
|
|
107
|
+
try {
|
|
108
|
+
this.cryptoRegexes.push(new RegExp(p, 'is'));
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
/* skip */
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
analyze(value, metadata) {
|
|
116
|
+
const code = value.trim();
|
|
117
|
+
if (!code) {
|
|
118
|
+
return {
|
|
119
|
+
actionType: 'code_eval',
|
|
120
|
+
findings: [],
|
|
121
|
+
shortCircuit: { safe: true, reason: 'Empty code' },
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
const lower = code.toLowerCase();
|
|
125
|
+
const _language = metadata?.language?.toLowerCase() ?? this.detectLanguage(code);
|
|
126
|
+
const findings = [];
|
|
127
|
+
const add = (primitive, score, reason, threatId) => {
|
|
128
|
+
findings.push({ primitive, score, reason, threatId });
|
|
129
|
+
};
|
|
130
|
+
// ── Safe short-circuit ──
|
|
131
|
+
if (code.length < 50) {
|
|
132
|
+
const hasRisky = this.backdoorPatterns.some((p) => lower.includes(p)) ||
|
|
133
|
+
this.backdoorRegexes.some((r) => r.test(code)) ||
|
|
134
|
+
this.vulnerabilityPatterns.some((p) => lower.includes(p)) ||
|
|
135
|
+
this.vulnerabilityRegexes.some((r) => r.test(code));
|
|
136
|
+
if (!hasRisky && this.safePatterns.some((p) => lower.includes(p))) {
|
|
137
|
+
return {
|
|
138
|
+
actionType: 'code_eval',
|
|
139
|
+
findings: [],
|
|
140
|
+
shortCircuit: { safe: true, reason: 'Short safe code' },
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Test file detection
|
|
145
|
+
if (this.isTestCode(code, lower)) {
|
|
146
|
+
const hasBackdoor = this.backdoorPatterns.some((p) => lower.includes(p)) ||
|
|
147
|
+
this.backdoorRegexes.some((r) => r.test(code));
|
|
148
|
+
if (!hasBackdoor) {
|
|
149
|
+
return {
|
|
150
|
+
actionType: 'code_eval',
|
|
151
|
+
findings: [],
|
|
152
|
+
shortCircuit: { safe: true, reason: 'Test code' },
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// ── G01: Backdoor detection ──
|
|
157
|
+
const hasBackdoorString = this.backdoorPatterns.some((p) => lower.includes(p));
|
|
158
|
+
const hasBackdoorRegex = this.backdoorRegexes.some((r) => r.test(code));
|
|
159
|
+
if (hasBackdoorString || hasBackdoorRegex) {
|
|
160
|
+
add('PERSISTENCE', 10, 'Backdoor injection — reverse shell, bind shell, or socket+exec pattern', 'G01');
|
|
161
|
+
}
|
|
162
|
+
// ── G02: Vulnerability injection ──
|
|
163
|
+
const vulnStringHits = this.vulnerabilityPatterns.filter((p) => lower.includes(p));
|
|
164
|
+
const vulnRegexHits = this.vulnerabilityRegexes.some((r) => r.test(code));
|
|
165
|
+
// SQL string concatenation detection
|
|
166
|
+
const hasSqlConcat = /(?:select|insert|update|delete|drop)\b.*['"].*\+.*\+/is.test(code) ||
|
|
167
|
+
/(?:query|sql)\s*=\s*['"].*['"].*\+/is.test(code);
|
|
168
|
+
if (vulnStringHits.length > 0 || vulnRegexHits || hasSqlConcat) {
|
|
169
|
+
// Regex hits are always considered risky context; string hits check comments
|
|
170
|
+
const isRiskyContext = vulnRegexHits ||
|
|
171
|
+
hasSqlConcat ||
|
|
172
|
+
(vulnStringHits.length > 0 && !this.isCommentOrDefinition(code, vulnStringHits));
|
|
173
|
+
if (isRiskyContext) {
|
|
174
|
+
const details = hasSqlConcat
|
|
175
|
+
? 'SQL string concatenation'
|
|
176
|
+
: vulnStringHits.join(', ') || 'dangerous function usage';
|
|
177
|
+
add('ESCALATION', 8, `Vulnerability injection — ${details}`, 'G02');
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// ── G03: Dependency confusion ──
|
|
181
|
+
const importPatterns = this.extractPackageNames(code);
|
|
182
|
+
const suspicious = importPatterns.filter((pkg) => this.dependencyConfusion.has(pkg.toLowerCase()));
|
|
183
|
+
if (suspicious.length > 0) {
|
|
184
|
+
add('DESTRUCTION', 7, `Dependency confusion — suspicious packages: ${suspicious.join(', ')}`, 'G03');
|
|
185
|
+
}
|
|
186
|
+
// ── G04: Obfuscation ──
|
|
187
|
+
const hasObfuscationString = this.obfuscationPatterns.some((p) => lower.includes(p));
|
|
188
|
+
const hasObfuscationRegex = this.obfuscationRegexes.some((r) => r.test(code));
|
|
189
|
+
if (hasObfuscationString || hasObfuscationRegex) {
|
|
190
|
+
// Check for long encoded strings (high confidence)
|
|
191
|
+
const hasLongEncoded = /[A-Za-z0-9+/=]{64,}/.test(code) || /(?:\\x[0-9a-f]{2}){8,}/i.test(code);
|
|
192
|
+
if (hasLongEncoded) {
|
|
193
|
+
add('MANIPULATION', 7, 'Obfuscated code — long encoded strings detected', 'G04');
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
add('MANIPULATION', 4, 'Potential obfuscation — encoding functions detected', 'G04');
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// ── G05: Phone-home code ──
|
|
200
|
+
if (this.phoneHomeRegexes.some((r) => r.test(code))) {
|
|
201
|
+
add('EXFILTRATION', 8, 'Phone-home code — HTTP request combined with file/env access', 'G05');
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
// Fallback: manual detection
|
|
205
|
+
const hasNetworkSend = /fetch|requests\.post|http\.request|urllib|axios\.post|XMLHttpRequest|curl_exec/i.test(code);
|
|
206
|
+
const hasDataRead = /readFile|readdir|process\.env|os\.environ|open\(/i.test(code);
|
|
207
|
+
if (hasNetworkSend && hasDataRead) {
|
|
208
|
+
add('EXFILTRATION', 7, 'Phone-home pattern — network send combined with local data access', 'G05');
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// ── G06: Insecure defaults ──
|
|
212
|
+
const insecureStringHits = this.insecureDefaults.filter((p) => lower.includes(p));
|
|
213
|
+
const insecureRegexHits = this.insecureRegexes.some((r) => r.test(code));
|
|
214
|
+
if (insecureStringHits.length > 0 || insecureRegexHits) {
|
|
215
|
+
add('ESCALATION', 6, `Insecure defaults — ${insecureStringHits.join(', ') || 'hardcoded credentials or disabled security'}`, 'G06');
|
|
216
|
+
}
|
|
217
|
+
// ── G07: Logic bombs ──
|
|
218
|
+
if (this.logicBombRegexes.some((r) => r.test(code))) {
|
|
219
|
+
add('PERSISTENCE', 9, 'Logic bomb — date/condition-triggered destructive action', 'G07');
|
|
220
|
+
}
|
|
221
|
+
// ── G08: Crypto wallet replacement ──
|
|
222
|
+
// Check for wallet address patterns in code (regex patterns, string literals, etc.)
|
|
223
|
+
const hasCryptoRegex = this.cryptoRegexes.some((r) => r.test(code));
|
|
224
|
+
// Also detect crypto wallet patterns mentioned as regex literals or string patterns
|
|
225
|
+
const hasCryptoContext = /(?:bc1|0x[0-9a-f]|1[13][a-km-z])[^\s]{10,}/i.test(code) ||
|
|
226
|
+
/wallet.*(?:replace|address)|(?:replace|swap).*(?:wallet|btc|eth|bitcoin|0x)/is.test(code);
|
|
227
|
+
if (hasCryptoRegex || hasCryptoContext) {
|
|
228
|
+
const hasReplace = /replace|swap|substitute|overwrite/i.test(code);
|
|
229
|
+
const hasWalletContext = /wallet|address|btc|eth|bitcoin|ethereum|crypto/i.test(code);
|
|
230
|
+
if (hasReplace && hasWalletContext) {
|
|
231
|
+
add('EXFILTRATION', 9, 'Crypto wallet replacement — wallet address patterns with replacement logic', 'G08');
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return { actionType: 'code_eval', findings };
|
|
235
|
+
}
|
|
236
|
+
isRegexPattern(pattern) {
|
|
237
|
+
return /[.*+?^${}()|[\]\\]/.test(pattern) && pattern !== '0.0.0.0';
|
|
238
|
+
}
|
|
239
|
+
detectLanguage(code) {
|
|
240
|
+
if (/^#!/.test(code) && /python|python3/.test(code))
|
|
241
|
+
return 'python';
|
|
242
|
+
if (/^#!/.test(code) && /node|deno|bun/.test(code))
|
|
243
|
+
return 'javascript';
|
|
244
|
+
if (/\bdef\s+\w+.*:$|import\s+\w+|from\s+\w+\s+import/m.test(code))
|
|
245
|
+
return 'python';
|
|
246
|
+
if (/\bfunction\s+\w+|const\s+\w+\s*=|let\s+\w+\s*=|=>\s*{/m.test(code))
|
|
247
|
+
return 'javascript';
|
|
248
|
+
if (/\bfunc\s+\w+|package\s+\w+|import\s*\(/m.test(code))
|
|
249
|
+
return 'go';
|
|
250
|
+
if (/\bfn\s+\w+|use\s+\w+::|let\s+mut\s+/m.test(code))
|
|
251
|
+
return 'rust';
|
|
252
|
+
if (/\bpublic\s+class|private\s+\w+|System\.out/m.test(code))
|
|
253
|
+
return 'java';
|
|
254
|
+
return 'unknown';
|
|
255
|
+
}
|
|
256
|
+
isTestCode(code, lower) {
|
|
257
|
+
const testIndicators = [
|
|
258
|
+
'import unittest',
|
|
259
|
+
'describe(',
|
|
260
|
+
'it(',
|
|
261
|
+
'test(',
|
|
262
|
+
'expect(',
|
|
263
|
+
'assert',
|
|
264
|
+
'def test_',
|
|
265
|
+
'#[test]',
|
|
266
|
+
'@Test',
|
|
267
|
+
];
|
|
268
|
+
return testIndicators.filter((t) => lower.includes(t.toLowerCase())).length >= 2;
|
|
269
|
+
}
|
|
270
|
+
isCommentOrDefinition(code, patterns) {
|
|
271
|
+
// Check if all matches are in comments or string definitions
|
|
272
|
+
for (const pattern of patterns) {
|
|
273
|
+
const lines = code.split('\n');
|
|
274
|
+
for (const line of lines) {
|
|
275
|
+
const trimmed = line.trim();
|
|
276
|
+
if (trimmed.toLowerCase().includes(pattern)) {
|
|
277
|
+
// Not a comment
|
|
278
|
+
if (!trimmed.startsWith('//') &&
|
|
279
|
+
!trimmed.startsWith('#') &&
|
|
280
|
+
!trimmed.startsWith('*') &&
|
|
281
|
+
!trimmed.startsWith('/*')) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
extractPackageNames(code) {
|
|
290
|
+
const packages = [];
|
|
291
|
+
// JS: require('pkg') or import ... from 'pkg'
|
|
292
|
+
const jsRequire = /require\s*\(\s*['"]([^'"./][^'"]*)['"]\s*\)/g;
|
|
293
|
+
const jsImport = /from\s+['"]([^'"./][^'"]*)['"]/g;
|
|
294
|
+
// Python: import pkg or from pkg import
|
|
295
|
+
const pyImport = /^(?:import|from)\s+([a-zA-Z_][a-zA-Z0-9_]*)/gm;
|
|
296
|
+
// Go: "pkg"
|
|
297
|
+
const goImport = /import\s+(?:\(\s*)?["']([^"']+)["']/g;
|
|
298
|
+
let match;
|
|
299
|
+
while ((match = jsRequire.exec(code)) !== null)
|
|
300
|
+
packages.push(match[1].split('/')[0]);
|
|
301
|
+
while ((match = jsImport.exec(code)) !== null)
|
|
302
|
+
packages.push(match[1].split('/')[0]);
|
|
303
|
+
while ((match = pyImport.exec(code)) !== null)
|
|
304
|
+
packages.push(match[1]);
|
|
305
|
+
while ((match = goImport.exec(code)) !== null)
|
|
306
|
+
packages.push(match[1]);
|
|
307
|
+
return packages;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=code.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code.js","sourceRoot":"","sources":["../../src/analyzers/code.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/analyzers/command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAmB,cAAc,EAAE,MAAM,WAAW,CAAC;AAc3E;;;;;GAKG;AACH,qBAAa,eAAgB,YAAW,QAAQ;IAC9C,QAAQ,CAAC,UAAU,EAAG,SAAS,CAAU;IAEzC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAyB;IAC5C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAc;IAC9C,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAc;IACrD,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAc;IACtD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAc;IACjD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAc;IACjD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAc;gBAEtC,QAAQ,EAAE,sBAAsB;IAU5C,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc;
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/analyzers/command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAmB,cAAc,EAAE,MAAM,WAAW,CAAC;AAc3E;;;;;GAKG;AACH,qBAAa,eAAgB,YAAW,QAAQ;IAC9C,QAAQ,CAAC,UAAU,EAAG,SAAS,CAAU;IAEzC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAyB;IAC5C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAc;IAC9C,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAc;IACrD,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAc;IACtD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAc;IACjD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAc;IACjD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAc;gBAEtC,QAAQ,EAAE,sBAAsB;IAU5C,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc;IAmZtC;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAqBhB;;OAEG;IACH,OAAO,CAAC,aAAa;IA0ErB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAuCvB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,wBAAwB;IAOhC,OAAO,CAAC,mBAAmB;IAe3B;;;OAGG;IACH,OAAO,CAAC,YAAY;CA6BrB"}
|
|
@@ -25,7 +25,11 @@ export class CommandAnalyzer {
|
|
|
25
25
|
analyze(value) {
|
|
26
26
|
const trimmed = value.trim();
|
|
27
27
|
if (!trimmed) {
|
|
28
|
-
return {
|
|
28
|
+
return {
|
|
29
|
+
actionType: 'command',
|
|
30
|
+
findings: [],
|
|
31
|
+
shortCircuit: { safe: true, reason: 'Empty command' },
|
|
32
|
+
};
|
|
29
33
|
}
|
|
30
34
|
const findings = [];
|
|
31
35
|
const add = (primitive, score, reason, threatId) => {
|
|
@@ -40,7 +44,11 @@ export class CommandAnalyzer {
|
|
|
40
44
|
if (segments.length === 1 && !hasPipe && !hasRedirect && !hasSubshell) {
|
|
41
45
|
const cmd = segments[0].command.toLowerCase();
|
|
42
46
|
if (this.safeCommandsSet.has(cmd) && !this.hasRiskyArgs(segments[0])) {
|
|
43
|
-
return {
|
|
47
|
+
return {
|
|
48
|
+
actionType: 'command',
|
|
49
|
+
findings: [],
|
|
50
|
+
shortCircuit: { safe: true, reason: 'Known safe command' },
|
|
51
|
+
};
|
|
44
52
|
}
|
|
45
53
|
}
|
|
46
54
|
// ── 1. Pipe-to-shell (C04) ────────────────────────────────────────
|
|
@@ -78,7 +86,7 @@ export class CommandAnalyzer {
|
|
|
78
86
|
if (this.destructiveCommandsSet.has(cmd) || this.destructiveCommandsSet.has(cmdBase)) {
|
|
79
87
|
// Check for ad-hoc adjustments first
|
|
80
88
|
if (cmd === 'rm') {
|
|
81
|
-
const hasRecursive = seg.args.some(a => ['-r', '-rf', '-fr', '--recursive', '-Rf', '-fR'].includes(a));
|
|
89
|
+
const hasRecursive = seg.args.some((a) => ['-r', '-rf', '-fr', '--recursive', '-Rf', '-fR'].includes(a));
|
|
82
90
|
const targetsCritical = this.targetsCriticalPath(seg.args);
|
|
83
91
|
if (hasRecursive && targetsCritical) {
|
|
84
92
|
add('DESTRUCTION', 9, `Recursive delete targeting critical path`, 'C01');
|
|
@@ -104,7 +112,7 @@ export class CommandAnalyzer {
|
|
|
104
112
|
// Dangerous flags on non-destructive commands
|
|
105
113
|
if (this.db.destructiveFlags[cmd]) {
|
|
106
114
|
for (const flag of this.db.destructiveFlags[cmd]) {
|
|
107
|
-
if (seg.args.some(a => a.includes(flag))) {
|
|
115
|
+
if (seg.args.some((a) => a.includes(flag))) {
|
|
108
116
|
// Skip if already detected above
|
|
109
117
|
if (cmd !== 'rm' && cmd !== 'dd') {
|
|
110
118
|
add('DESTRUCTION', 7, `Dangerous flag ${flag} used with ${cmd}`, 'C01');
|
|
@@ -126,8 +134,8 @@ export class CommandAnalyzer {
|
|
|
126
134
|
const cmd = seg.command.toLowerCase();
|
|
127
135
|
if (cmd === 'scp' || cmd === 'rsync') {
|
|
128
136
|
// scp/rsync with a remote target
|
|
129
|
-
if (seg.args.some(a => a.includes('@') || a.includes(':'))) {
|
|
130
|
-
if (!findings.some(f => f.threatId === 'C02')) {
|
|
137
|
+
if (seg.args.some((a) => a.includes('@') || a.includes(':'))) {
|
|
138
|
+
if (!findings.some((f) => f.threatId === 'C02')) {
|
|
131
139
|
add('EXFILTRATION', 8, `${cmd} transferring data to remote host`, 'C02');
|
|
132
140
|
}
|
|
133
141
|
}
|
|
@@ -135,22 +143,50 @@ export class CommandAnalyzer {
|
|
|
135
143
|
}
|
|
136
144
|
// ── 8. Credential harvesting (C18) ────────────────────────────────
|
|
137
145
|
const credentialPatterns = [
|
|
138
|
-
'/etc/shadow',
|
|
139
|
-
'
|
|
140
|
-
'.
|
|
141
|
-
'
|
|
142
|
-
'.
|
|
146
|
+
'/etc/shadow',
|
|
147
|
+
'/etc/passwd',
|
|
148
|
+
'.ssh/id_rsa',
|
|
149
|
+
'.ssh/id_ed25519',
|
|
150
|
+
'.ssh/id_dsa',
|
|
151
|
+
'.ssh/id_ecdsa',
|
|
152
|
+
'.ssh/authorized_keys',
|
|
153
|
+
'.env',
|
|
154
|
+
'.pem',
|
|
155
|
+
'.key',
|
|
156
|
+
'.p12',
|
|
157
|
+
'.pfx',
|
|
158
|
+
'credentials',
|
|
159
|
+
'.aws/credentials',
|
|
160
|
+
'.docker/config.json',
|
|
161
|
+
'.kube/config',
|
|
162
|
+
'.gnupg/',
|
|
163
|
+
'.netrc',
|
|
143
164
|
];
|
|
144
165
|
for (const cred of credentialPatterns) {
|
|
145
166
|
if (lower.includes(cred)) {
|
|
146
167
|
// Only flag if reading, not just referencing in a safe context
|
|
147
|
-
const isReading = segments.some(s => {
|
|
168
|
+
const isReading = segments.some((s) => {
|
|
148
169
|
const cmd = s.command.toLowerCase();
|
|
149
|
-
return [
|
|
170
|
+
return [
|
|
171
|
+
'cat',
|
|
172
|
+
'less',
|
|
173
|
+
'more',
|
|
174
|
+
'head',
|
|
175
|
+
'tail',
|
|
176
|
+
'cp',
|
|
177
|
+
'scp',
|
|
178
|
+
'rsync',
|
|
179
|
+
'curl',
|
|
180
|
+
'wget',
|
|
181
|
+
'base64',
|
|
182
|
+
].includes(cmd);
|
|
150
183
|
});
|
|
151
184
|
// Also flag file redirection of sensitive files
|
|
152
185
|
const hasOutputRedirect = hasRedirect && lower.includes(cred);
|
|
153
|
-
if (isReading ||
|
|
186
|
+
if (isReading ||
|
|
187
|
+
hasOutputRedirect ||
|
|
188
|
+
lower.includes(`-d @`) ||
|
|
189
|
+
lower.includes('--upload-file')) {
|
|
154
190
|
add('EXFILTRATION', 8, `Accessing sensitive credential file (${cred})`, 'C18');
|
|
155
191
|
break;
|
|
156
192
|
}
|
|
@@ -163,8 +199,13 @@ export class CommandAnalyzer {
|
|
|
163
199
|
if (cmd === 'sudo') {
|
|
164
200
|
// sudo apt install / sudo brew install — common, reduced
|
|
165
201
|
const subCmd = seg.args[0]?.toLowerCase();
|
|
166
|
-
if (subCmd === 'apt' ||
|
|
167
|
-
|
|
202
|
+
if (subCmd === 'apt' ||
|
|
203
|
+
subCmd === 'apt-get' ||
|
|
204
|
+
subCmd === 'brew' ||
|
|
205
|
+
subCmd === 'yum' ||
|
|
206
|
+
subCmd === 'dnf' ||
|
|
207
|
+
subCmd === 'pacman') {
|
|
208
|
+
if (seg.args.some((a) => a.toLowerCase() === 'install')) {
|
|
168
209
|
add('ESCALATION', 2, `sudo ${subCmd} install — common system administration`, 'C05');
|
|
169
210
|
}
|
|
170
211
|
else {
|
|
@@ -186,15 +227,15 @@ export class CommandAnalyzer {
|
|
|
186
227
|
}
|
|
187
228
|
// chmod with dangerous values on critical paths
|
|
188
229
|
if (cmd === 'chmod') {
|
|
189
|
-
const hasRiskyPerm = seg.args.some(a => ['777', '000', 'a+rwx'].includes(a));
|
|
230
|
+
const hasRiskyPerm = seg.args.some((a) => ['777', '000', 'a+rwx'].includes(a));
|
|
190
231
|
const targetsCritical = this.targetsCriticalPath(seg.args);
|
|
191
232
|
if (hasRiskyPerm && targetsCritical) {
|
|
192
|
-
if (!findings.some(f => f.threatId === 'C05' && f.score >= 8)) {
|
|
233
|
+
if (!findings.some((f) => f.threatId === 'C05' && f.score >= 8)) {
|
|
193
234
|
add('ESCALATION', 8, `chmod with dangerous permissions on critical path`, 'C05');
|
|
194
235
|
}
|
|
195
236
|
}
|
|
196
237
|
else if (hasRiskyPerm) {
|
|
197
|
-
if (!findings.some(f => f.threatId === 'C05' && f.score >= 6)) {
|
|
238
|
+
if (!findings.some((f) => f.threatId === 'C05' && f.score >= 6)) {
|
|
198
239
|
add('ESCALATION', 4, `chmod with broad permissions`, 'C05');
|
|
199
240
|
}
|
|
200
241
|
}
|
|
@@ -214,15 +255,15 @@ export class CommandAnalyzer {
|
|
|
214
255
|
// ── 11. Process injection (C15) ───────────────────────────────────
|
|
215
256
|
for (const seg of segments) {
|
|
216
257
|
const cmd = seg.command.toLowerCase();
|
|
217
|
-
if (cmd === 'gdb' && seg.args.some(a => a === '-p' || a === '--pid')) {
|
|
258
|
+
if (cmd === 'gdb' && seg.args.some((a) => a === '-p' || a === '--pid')) {
|
|
218
259
|
add('ESCALATION', 8, 'Process injection via gdb attach', 'C15');
|
|
219
260
|
}
|
|
220
|
-
if (cmd === 'strace' && seg.args.some(a => a === '-p')) {
|
|
261
|
+
if (cmd === 'strace' && seg.args.some((a) => a === '-p')) {
|
|
221
262
|
add('ESCALATION', 8, 'Process tracing via strace', 'C15');
|
|
222
263
|
}
|
|
223
264
|
}
|
|
224
265
|
// LD_PRELOAD as inline env var (not export)
|
|
225
|
-
if (/\bLD_PRELOAD=\S+\s+\S/.test(trimmed) && !findings.some(f => f.threatId === 'C15')) {
|
|
266
|
+
if (/\bLD_PRELOAD=\S+\s+\S/.test(trimmed) && !findings.some((f) => f.threatId === 'C15')) {
|
|
226
267
|
add('ESCALATION', 8, 'Process injection via LD_PRELOAD', 'C15');
|
|
227
268
|
}
|
|
228
269
|
// ── 12. Persistence — cron (C06) ──────────────────────────────────
|
|
@@ -233,20 +274,26 @@ export class CommandAnalyzer {
|
|
|
233
274
|
}
|
|
234
275
|
}
|
|
235
276
|
if (lower.includes('/etc/cron') || lower.includes('/var/spool/cron')) {
|
|
236
|
-
if (!findings.some(f => f.threatId === 'C06')) {
|
|
277
|
+
if (!findings.some((f) => f.threatId === 'C06')) {
|
|
237
278
|
add('PERSISTENCE', 7, 'Writing to cron directory — persistent execution', 'C06');
|
|
238
279
|
}
|
|
239
280
|
}
|
|
240
281
|
// ── 13. Persistence — shell config (C07) ──────────────────────────
|
|
241
282
|
const shellConfigs = ['.bashrc', '.zshrc', '.profile', '.bash_profile', '.bash_login'];
|
|
242
283
|
for (const config of shellConfigs) {
|
|
243
|
-
if (lower.includes(config) &&
|
|
284
|
+
if (lower.includes(config) &&
|
|
285
|
+
(hasRedirect || lower.includes('echo') || lower.includes('tee'))) {
|
|
244
286
|
add('PERSISTENCE', 6, `Modifying shell config file (${config}) — persistence`, 'C07');
|
|
245
287
|
break;
|
|
246
288
|
}
|
|
247
289
|
}
|
|
248
290
|
// ── 14. Git hook injection (C11) ──────────────────────────────────
|
|
249
|
-
if (lower.includes('.git/hooks/') &&
|
|
291
|
+
if (lower.includes('.git/hooks/') &&
|
|
292
|
+
(hasRedirect ||
|
|
293
|
+
lower.includes('echo') ||
|
|
294
|
+
lower.includes('tee') ||
|
|
295
|
+
lower.includes('cp') ||
|
|
296
|
+
lower.includes('chmod'))) {
|
|
250
297
|
add('PERSISTENCE', 6, 'Git hook modification — code runs on git operations', 'C11');
|
|
251
298
|
}
|
|
252
299
|
// ── 15. Environment poisoning (C10) ───────────────────────────────
|
|
@@ -254,7 +301,7 @@ export class CommandAnalyzer {
|
|
|
254
301
|
add('PERSISTENCE', 6, 'PATH environment variable modification', 'C10');
|
|
255
302
|
}
|
|
256
303
|
if (/\bexport\s+LD_PRELOAD=/.test(trimmed)) {
|
|
257
|
-
if (!findings.some(f => f.threatId === 'C15')) {
|
|
304
|
+
if (!findings.some((f) => f.threatId === 'C15')) {
|
|
258
305
|
add('PERSISTENCE', 6, 'LD_PRELOAD environment variable set', 'C10');
|
|
259
306
|
}
|
|
260
307
|
}
|
|
@@ -280,7 +327,7 @@ export class CommandAnalyzer {
|
|
|
280
327
|
for (const seg of segments) {
|
|
281
328
|
const cmd = seg.command.toLowerCase();
|
|
282
329
|
if (cmd === 'nc' || cmd === 'ncat' || cmd === 'netcat') {
|
|
283
|
-
if (seg.args.some(a => a === '-l' || a === '-lp' || a.startsWith('-l'))) {
|
|
330
|
+
if (seg.args.some((a) => a === '-l' || a === '-lp' || a.startsWith('-l'))) {
|
|
284
331
|
add('ESCALATION', 5, 'Network listener opened', 'C17');
|
|
285
332
|
}
|
|
286
333
|
}
|
|
@@ -290,14 +337,17 @@ export class CommandAnalyzer {
|
|
|
290
337
|
}
|
|
291
338
|
// python/python3 -m http.server
|
|
292
339
|
if (lower.includes('http.server') || lower.includes('simplehttpserver')) {
|
|
293
|
-
if (!findings.some(f => f.threatId === 'C17')) {
|
|
340
|
+
if (!findings.some((f) => f.threatId === 'C17')) {
|
|
294
341
|
add('ESCALATION', 5, 'HTTP server started — exposes files on network', 'C17');
|
|
295
342
|
}
|
|
296
343
|
}
|
|
297
344
|
// ── 18. History tampering (C12) ───────────────────────────────────
|
|
298
|
-
if (lower.includes('history -c') ||
|
|
299
|
-
lower.includes('rm
|
|
300
|
-
lower.includes('
|
|
345
|
+
if (lower.includes('history -c') ||
|
|
346
|
+
lower.includes('rm ~/.bash_history') ||
|
|
347
|
+
lower.includes('rm -f ~/.bash_history') ||
|
|
348
|
+
lower.includes('unset histfile') ||
|
|
349
|
+
lower.includes('export histfile=/dev/null') ||
|
|
350
|
+
lower.includes('set +o history')) {
|
|
301
351
|
add('MANIPULATION', 4, 'Command history tampering detected', 'C12');
|
|
302
352
|
}
|
|
303
353
|
// ── 19. Disk filling (C16) ────────────────────────────────────────
|
|
@@ -307,7 +357,7 @@ export class CommandAnalyzer {
|
|
|
307
357
|
// dd writing to a file (not device) — disk filling
|
|
308
358
|
const hasDev = seg.raw.toLowerCase().includes('of=/dev/');
|
|
309
359
|
const hasOf = seg.raw.toLowerCase().includes('of=');
|
|
310
|
-
if (hasOf && !hasDev && !findings.some(f => f.threatId === 'C01' && f.score >= 9)) {
|
|
360
|
+
if (hasOf && !hasDev && !findings.some((f) => f.threatId === 'C01' && f.score >= 9)) {
|
|
311
361
|
add('DESTRUCTION', 5, 'dd writing to file — potential disk filling', 'C16');
|
|
312
362
|
}
|
|
313
363
|
}
|
|
@@ -318,10 +368,10 @@ export class CommandAnalyzer {
|
|
|
318
368
|
// Handle multi-word package managers like "go install"
|
|
319
369
|
const fullCmd = `${cmd} ${seg.args[0] || ''}`.trim().toLowerCase();
|
|
320
370
|
if (this.packageManagersSet.has(cmd) || this.packageManagersSet.has(fullCmd)) {
|
|
321
|
-
const isInstall = seg.args.some(a => ['install', 'add', 'i'].includes(a.toLowerCase()));
|
|
371
|
+
const isInstall = seg.args.some((a) => ['install', 'add', 'i'].includes(a.toLowerCase()));
|
|
322
372
|
if (isInstall || fullCmd.startsWith('go install')) {
|
|
323
373
|
// Skip if already covered by safe commands (npm test, etc.)
|
|
324
|
-
if (!findings.some(f => f.threatId === 'C20')) {
|
|
374
|
+
if (!findings.some((f) => f.threatId === 'C20')) {
|
|
325
375
|
add('DESTRUCTION', 3, `Package manager install (${cmd}) — may run arbitrary scripts`, 'C20');
|
|
326
376
|
}
|
|
327
377
|
}
|
|
@@ -474,11 +524,13 @@ export class CommandAnalyzer {
|
|
|
474
524
|
}
|
|
475
525
|
isEncodedCommand(lower) {
|
|
476
526
|
// base64 -d | bash/sh
|
|
477
|
-
if (/base64\s+(-d|--decode)/.test(lower) &&
|
|
527
|
+
if (/base64\s+(-d|--decode)/.test(lower) &&
|
|
528
|
+
this.db.pipeToShell.some((p) => lower.includes(p.toLowerCase()))) {
|
|
478
529
|
return true;
|
|
479
530
|
}
|
|
480
531
|
// eval $(...) with encoding
|
|
481
|
-
if (/eval\s+\$\(/.test(lower) &&
|
|
532
|
+
if (/eval\s+\$\(/.test(lower) &&
|
|
533
|
+
(lower.includes('base64') || lower.includes('xxd') || lower.includes('echo'))) {
|
|
482
534
|
return true;
|
|
483
535
|
}
|
|
484
536
|
// eval "$(base64 ...)"
|
|
@@ -517,17 +569,17 @@ export class CommandAnalyzer {
|
|
|
517
569
|
*/
|
|
518
570
|
hasRiskyArgs(seg) {
|
|
519
571
|
const cmd = seg.command.toLowerCase();
|
|
520
|
-
const argsLower = seg.args.map(a => a.toLowerCase());
|
|
572
|
+
const argsLower = seg.args.map((a) => a.toLowerCase());
|
|
521
573
|
// Check if safe command is reading sensitive credentials
|
|
522
574
|
if (['cat', 'less', 'more', 'head', 'tail'].includes(cmd)) {
|
|
523
575
|
const credFiles = ['/etc/shadow', '.ssh/id_rsa', '.ssh/id_ed25519', '.env', '.pem', '.key'];
|
|
524
|
-
if (seg.args.some(a => credFiles.some(c => a.toLowerCase().includes(c)))) {
|
|
576
|
+
if (seg.args.some((a) => credFiles.some((c) => a.toLowerCase().includes(c)))) {
|
|
525
577
|
return true;
|
|
526
578
|
}
|
|
527
579
|
}
|
|
528
580
|
// Package managers with install subcommand
|
|
529
581
|
if (this.packageManagersSet.has(cmd)) {
|
|
530
|
-
if (argsLower.some(a => ['install', 'add', 'i'].includes(a))) {
|
|
582
|
+
if (argsLower.some((a) => ['install', 'add', 'i'].includes(a))) {
|
|
531
583
|
return true;
|
|
532
584
|
}
|
|
533
585
|
}
|