@kairosinternational/watchman 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/PHASE_3A_COMPLETE.md +63 -0
- package/dist/engine.d.ts +9 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +99 -0
- package/dist/engine.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/scanners/ai-tool-integrity/index.d.ts +2 -0
- package/dist/scanners/ai-tool-integrity/index.d.ts.map +1 -0
- package/dist/scanners/ai-tool-integrity/index.js +6 -0
- package/dist/scanners/ai-tool-integrity/index.js.map +1 -0
- package/dist/scanners/ai-tool-integrity/patterns/injection-signatures.d.ts +7 -0
- package/dist/scanners/ai-tool-integrity/patterns/injection-signatures.d.ts.map +1 -0
- package/dist/scanners/ai-tool-integrity/patterns/injection-signatures.js +51 -0
- package/dist/scanners/ai-tool-integrity/patterns/injection-signatures.js.map +1 -0
- package/dist/scanners/ai-tool-integrity/rules/prompt-injection.rule.d.ts +3 -0
- package/dist/scanners/ai-tool-integrity/rules/prompt-injection.rule.d.ts.map +1 -0
- package/dist/scanners/ai-tool-integrity/rules/prompt-injection.rule.js +49 -0
- package/dist/scanners/ai-tool-integrity/rules/prompt-injection.rule.js.map +1 -0
- package/dist/scanners/ai-tool-integrity/rules/tool-manifest-drift.rule.d.ts +3 -0
- package/dist/scanners/ai-tool-integrity/rules/tool-manifest-drift.rule.d.ts.map +1 -0
- package/dist/scanners/ai-tool-integrity/rules/tool-manifest-drift.rule.js +71 -0
- package/dist/scanners/ai-tool-integrity/rules/tool-manifest-drift.rule.js.map +1 -0
- package/dist/scanners/ai-tool-integrity/rules/unauthorized-model-call.rule.d.ts +3 -0
- package/dist/scanners/ai-tool-integrity/rules/unauthorized-model-call.rule.d.ts.map +1 -0
- package/dist/scanners/ai-tool-integrity/rules/unauthorized-model-call.rule.js +56 -0
- package/dist/scanners/ai-tool-integrity/rules/unauthorized-model-call.rule.js.map +1 -0
- package/dist/scanners/ai-tool-integrity/scanner.d.ts +3 -0
- package/dist/scanners/ai-tool-integrity/scanner.d.ts.map +1 -0
- package/dist/scanners/ai-tool-integrity/scanner.js +26 -0
- package/dist/scanners/ai-tool-integrity/scanner.js.map +1 -0
- package/dist/scanners/dependency-integrity/index.d.ts +2 -0
- package/dist/scanners/dependency-integrity/index.d.ts.map +1 -0
- package/dist/scanners/dependency-integrity/index.js +6 -0
- package/dist/scanners/dependency-integrity/index.js.map +1 -0
- package/dist/scanners/dependency-integrity/patterns/known-typosquats.d.ts +8 -0
- package/dist/scanners/dependency-integrity/patterns/known-typosquats.d.ts.map +1 -0
- package/dist/scanners/dependency-integrity/patterns/known-typosquats.js +38 -0
- package/dist/scanners/dependency-integrity/patterns/known-typosquats.js.map +1 -0
- package/dist/scanners/dependency-integrity/rules/hash-validation.rule.d.ts +3 -0
- package/dist/scanners/dependency-integrity/rules/hash-validation.rule.d.ts.map +1 -0
- package/dist/scanners/dependency-integrity/rules/hash-validation.rule.js +64 -0
- package/dist/scanners/dependency-integrity/rules/hash-validation.rule.js.map +1 -0
- package/dist/scanners/dependency-integrity/rules/transitive-drift.rule.d.ts +3 -0
- package/dist/scanners/dependency-integrity/rules/transitive-drift.rule.d.ts.map +1 -0
- package/dist/scanners/dependency-integrity/rules/transitive-drift.rule.js +69 -0
- package/dist/scanners/dependency-integrity/rules/transitive-drift.rule.js.map +1 -0
- package/dist/scanners/dependency-integrity/rules/typosquat-check.rule.d.ts +3 -0
- package/dist/scanners/dependency-integrity/rules/typosquat-check.rule.d.ts.map +1 -0
- package/dist/scanners/dependency-integrity/rules/typosquat-check.rule.js +94 -0
- package/dist/scanners/dependency-integrity/rules/typosquat-check.rule.js.map +1 -0
- package/dist/scanners/dependency-integrity/scanner.d.ts +3 -0
- package/dist/scanners/dependency-integrity/scanner.d.ts.map +1 -0
- package/dist/scanners/dependency-integrity/scanner.js +26 -0
- package/dist/scanners/dependency-integrity/scanner.js.map +1 -0
- package/dist/scanners/runtime-monitor/index.d.ts +2 -0
- package/dist/scanners/runtime-monitor/index.d.ts.map +1 -0
- package/dist/scanners/runtime-monitor/index.js +6 -0
- package/dist/scanners/runtime-monitor/index.js.map +1 -0
- package/dist/scanners/runtime-monitor/patterns/known-bad-destinations.d.ts +8 -0
- package/dist/scanners/runtime-monitor/patterns/known-bad-destinations.d.ts.map +1 -0
- package/dist/scanners/runtime-monitor/patterns/known-bad-destinations.js +52 -0
- package/dist/scanners/runtime-monitor/patterns/known-bad-destinations.js.map +1 -0
- package/dist/scanners/runtime-monitor/rules/filesystem-access.rule.d.ts +3 -0
- package/dist/scanners/runtime-monitor/rules/filesystem-access.rule.d.ts.map +1 -0
- package/dist/scanners/runtime-monitor/rules/filesystem-access.rule.js +68 -0
- package/dist/scanners/runtime-monitor/rules/filesystem-access.rule.js.map +1 -0
- package/dist/scanners/runtime-monitor/rules/outbound-network.rule.d.ts +3 -0
- package/dist/scanners/runtime-monitor/rules/outbound-network.rule.d.ts.map +1 -0
- package/dist/scanners/runtime-monitor/rules/outbound-network.rule.js +62 -0
- package/dist/scanners/runtime-monitor/rules/outbound-network.rule.js.map +1 -0
- package/dist/scanners/runtime-monitor/rules/process-spawn.rule.d.ts +3 -0
- package/dist/scanners/runtime-monitor/rules/process-spawn.rule.d.ts.map +1 -0
- package/dist/scanners/runtime-monitor/rules/process-spawn.rule.js +55 -0
- package/dist/scanners/runtime-monitor/rules/process-spawn.rule.js.map +1 -0
- package/dist/scanners/runtime-monitor/rules/resource-anomaly.rule.d.ts +3 -0
- package/dist/scanners/runtime-monitor/rules/resource-anomaly.rule.d.ts.map +1 -0
- package/dist/scanners/runtime-monitor/rules/resource-anomaly.rule.js +76 -0
- package/dist/scanners/runtime-monitor/rules/resource-anomaly.rule.js.map +1 -0
- package/dist/scanners/runtime-monitor/scanner.d.ts +3 -0
- package/dist/scanners/runtime-monitor/scanner.d.ts.map +1 -0
- package/dist/scanners/runtime-monitor/scanner.js +28 -0
- package/dist/scanners/runtime-monitor/scanner.js.map +1 -0
- package/dist/scanners/secrets-exposure/index.d.ts +2 -0
- package/dist/scanners/secrets-exposure/index.d.ts.map +1 -0
- package/dist/scanners/secrets-exposure/index.js +6 -0
- package/dist/scanners/secrets-exposure/index.js.map +1 -0
- package/dist/scanners/secrets-exposure/patterns/secret-signatures.d.ts +7 -0
- package/dist/scanners/secrets-exposure/patterns/secret-signatures.d.ts.map +1 -0
- package/dist/scanners/secrets-exposure/patterns/secret-signatures.js +76 -0
- package/dist/scanners/secrets-exposure/patterns/secret-signatures.js.map +1 -0
- package/dist/scanners/secrets-exposure/rules/entropy-check.rule.d.ts +3 -0
- package/dist/scanners/secrets-exposure/rules/entropy-check.rule.d.ts.map +1 -0
- package/dist/scanners/secrets-exposure/rules/entropy-check.rule.js +77 -0
- package/dist/scanners/secrets-exposure/rules/entropy-check.rule.js.map +1 -0
- package/dist/scanners/secrets-exposure/rules/known-patterns.rule.d.ts +3 -0
- package/dist/scanners/secrets-exposure/rules/known-patterns.rule.d.ts.map +1 -0
- package/dist/scanners/secrets-exposure/rules/known-patterns.rule.js +62 -0
- package/dist/scanners/secrets-exposure/rules/known-patterns.rule.js.map +1 -0
- package/dist/scanners/secrets-exposure/rules/response-echo.rule.d.ts +3 -0
- package/dist/scanners/secrets-exposure/rules/response-echo.rule.d.ts.map +1 -0
- package/dist/scanners/secrets-exposure/rules/response-echo.rule.js +67 -0
- package/dist/scanners/secrets-exposure/rules/response-echo.rule.js.map +1 -0
- package/dist/scanners/secrets-exposure/scanner.d.ts +3 -0
- package/dist/scanners/secrets-exposure/scanner.d.ts.map +1 -0
- package/dist/scanners/secrets-exposure/scanner.js +26 -0
- package/dist/scanners/secrets-exposure/scanner.js.map +1 -0
- package/dist/types/config.types.d.ts +22 -0
- package/dist/types/config.types.d.ts.map +1 -0
- package/dist/types/config.types.js +15 -0
- package/dist/types/config.types.js.map +1 -0
- package/dist/types/context.types.d.ts +23 -0
- package/dist/types/context.types.d.ts.map +1 -0
- package/dist/types/context.types.js +3 -0
- package/dist/types/context.types.js.map +1 -0
- package/dist/types/finding.types.d.ts +33 -0
- package/dist/types/finding.types.d.ts.map +1 -0
- package/dist/types/finding.types.js +3 -0
- package/dist/types/finding.types.js.map +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +32 -0
- package/src/engine.ts +129 -0
- package/src/index.ts +28 -0
- package/src/scanners/ai-tool-integrity/index.ts +1 -0
- package/src/scanners/ai-tool-integrity/patterns/injection-signatures.ts +53 -0
- package/src/scanners/ai-tool-integrity/rules/prompt-injection.rule.ts +50 -0
- package/src/scanners/ai-tool-integrity/rules/tool-manifest-drift.rule.ts +81 -0
- package/src/scanners/ai-tool-integrity/rules/unauthorized-model-call.rule.ts +59 -0
- package/src/scanners/ai-tool-integrity/scanner.ts +25 -0
- package/src/scanners/dependency-integrity/index.ts +1 -0
- package/src/scanners/dependency-integrity/patterns/known-typosquats.ts +41 -0
- package/src/scanners/dependency-integrity/rules/hash-validation.rule.ts +72 -0
- package/src/scanners/dependency-integrity/rules/transitive-drift.rule.ts +71 -0
- package/src/scanners/dependency-integrity/rules/typosquat-check.rule.ts +100 -0
- package/src/scanners/dependency-integrity/scanner.ts +25 -0
- package/src/scanners/runtime-monitor/index.ts +1 -0
- package/src/scanners/runtime-monitor/patterns/known-bad-destinations.ts +55 -0
- package/src/scanners/runtime-monitor/rules/filesystem-access.rule.ts +74 -0
- package/src/scanners/runtime-monitor/rules/outbound-network.rule.ts +67 -0
- package/src/scanners/runtime-monitor/rules/process-spawn.rule.ts +58 -0
- package/src/scanners/runtime-monitor/rules/resource-anomaly.rule.ts +79 -0
- package/src/scanners/runtime-monitor/scanner.ts +27 -0
- package/src/scanners/secrets-exposure/index.ts +1 -0
- package/src/scanners/secrets-exposure/patterns/secret-signatures.ts +78 -0
- package/src/scanners/secrets-exposure/rules/entropy-check.rule.ts +79 -0
- package/src/scanners/secrets-exposure/rules/known-patterns.rule.ts +64 -0
- package/src/scanners/secrets-exposure/rules/response-echo.rule.ts +70 -0
- package/src/scanners/secrets-exposure/scanner.ts +25 -0
- package/src/types/config.types.ts +40 -0
- package/src/types/context.types.ts +25 -0
- package/src/types/finding.types.ts +36 -0
- package/src/types/index.ts +21 -0
- package/tsconfig.json +21 -0
- package/watchman.config.ts +16 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SUBSTITUTION_PAIRS = exports.KNOWN_TYPOSQUATS = void 0;
|
|
4
|
+
// Well-documented typosquat packages from public advisories
|
|
5
|
+
exports.KNOWN_TYPOSQUATS = [
|
|
6
|
+
{ malicious: 'crossenv', legitimate: 'cross-env', technique: 'typosquat' },
|
|
7
|
+
{ malicious: 'cross-env.js', legitimate: 'cross-env', technique: 'combosquat' },
|
|
8
|
+
{ malicious: 'event-stream', legitimate: 'event-stream', technique: 'starjack' },
|
|
9
|
+
{ malicious: 'flatmap-stream', legitimate: 'flatmap-stream', technique: 'starjack' },
|
|
10
|
+
{ malicious: 'babelcli', legitimate: '@babel/cli', technique: 'scope-confusion' },
|
|
11
|
+
{ malicious: 'eslint-scope', legitimate: 'eslint-scope', technique: 'starjack' },
|
|
12
|
+
{ malicious: 'getcookies', legitimate: 'get-cookies', technique: 'typosquat' },
|
|
13
|
+
{ malicious: 'http-proxy.js', legitimate: 'http-proxy', technique: 'combosquat' },
|
|
14
|
+
{ malicious: 'mongose', legitimate: 'mongoose', technique: 'typosquat' },
|
|
15
|
+
{ malicious: 'mssql.js', legitimate: 'mssql', technique: 'combosquat' },
|
|
16
|
+
{ malicious: 'node-fabric', legitimate: 'fabric', technique: 'combosquat' },
|
|
17
|
+
{ malicious: 'node-opencv', legitimate: 'opencv', technique: 'combosquat' },
|
|
18
|
+
{ malicious: 'nodefabric', legitimate: 'fabric', technique: 'typosquat' },
|
|
19
|
+
{ malicious: 'nodemailer-js', legitimate: 'nodemailer', technique: 'combosquat' },
|
|
20
|
+
{ malicious: 'noderequest', legitimate: 'request', technique: 'combosquat' },
|
|
21
|
+
{ malicious: 'nodesass', legitimate: 'node-sass', technique: 'typosquat' },
|
|
22
|
+
{ malicious: 'proxy.js', legitimate: 'proxy', technique: 'combosquat' },
|
|
23
|
+
{ malicious: 'shadowsock', legitimate: 'shadowsocks', technique: 'typosquat' },
|
|
24
|
+
{ malicious: 'smb', legitimate: 'smb2', technique: 'typosquat' },
|
|
25
|
+
{ malicious: 'sqliter', legitimate: 'sqlite3', technique: 'typosquat' },
|
|
26
|
+
{ malicious: 'tkinter', legitimate: 'tkinter', technique: 'scope-confusion' },
|
|
27
|
+
];
|
|
28
|
+
// Common character substitution patterns for fuzzy detection
|
|
29
|
+
exports.SUBSTITUTION_PAIRS = [
|
|
30
|
+
['0', 'o'],
|
|
31
|
+
['1', 'l'],
|
|
32
|
+
['rn', 'm'],
|
|
33
|
+
['-', ''],
|
|
34
|
+
['_', '-'],
|
|
35
|
+
['.js', ''],
|
|
36
|
+
['node-', ''],
|
|
37
|
+
];
|
|
38
|
+
//# sourceMappingURL=known-typosquats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"known-typosquats.js","sourceRoot":"","sources":["../../../../src/scanners/dependency-integrity/patterns/known-typosquats.ts"],"names":[],"mappings":";;;AAMA,4DAA4D;AAC/C,QAAA,gBAAgB,GAAqB;IAChD,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE;IAC1E,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE;IAC/E,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE;IAChF,EAAE,SAAS,EAAE,gBAAgB,EAAE,UAAU,EAAE,gBAAgB,EAAE,SAAS,EAAE,UAAU,EAAE;IACpF,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE;IACjF,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE;IAChF,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE;IAC9E,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE;IACjF,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE;IACxE,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE;IACvE,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE;IAC3E,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE;IAC3E,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE;IACzE,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE;IACjF,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE;IAC5E,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE;IAC1E,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE;IACvE,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE;IAC9E,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE;IAChE,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE;IACvE,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,iBAAiB,EAAE;CAC9E,CAAC;AAEF,6DAA6D;AAChD,QAAA,kBAAkB,GAAuB;IACpD,CAAC,GAAG,EAAE,GAAG,CAAC;IACV,CAAC,GAAG,EAAE,GAAG,CAAC;IACV,CAAC,IAAI,EAAE,GAAG,CAAC;IACX,CAAC,GAAG,EAAE,EAAE,CAAC;IACT,CAAC,GAAG,EAAE,GAAG,CAAC;IACV,CAAC,KAAK,EAAE,EAAE,CAAC;IACX,CAAC,OAAO,EAAE,EAAE,CAAC;CACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash-validation.rule.d.ts","sourceRoot":"","sources":["../../../../src/scanners/dependency-integrity/rules/hash-validation.rule.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAe,MAAM,yBAAyB,CAAC;AASjE,eAAO,MAAM,kBAAkB,EAAE,IA4DhC,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hashValidationRule = void 0;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
exports.hashValidationRule = {
|
|
7
|
+
id: 'hash-validation',
|
|
8
|
+
name: 'Lockfile Hash Validation',
|
|
9
|
+
description: 'Verifies that lockfile entries have integrity hashes and use secure algorithms',
|
|
10
|
+
async run(ctx) {
|
|
11
|
+
const lockfiles = ctx.files.filter((f) => (0, node_path_1.basename)(f) === 'package-lock.json');
|
|
12
|
+
for (const file of lockfiles) {
|
|
13
|
+
let content;
|
|
14
|
+
try {
|
|
15
|
+
content = await (0, promises_1.readFile)(file, 'utf-8');
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
let parsed;
|
|
21
|
+
try {
|
|
22
|
+
parsed = JSON.parse(content);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
ctx.addFinding({
|
|
26
|
+
rule: 'hash-validation',
|
|
27
|
+
severity: 'high',
|
|
28
|
+
message: 'Lockfile is not valid JSON — may have been tampered with',
|
|
29
|
+
location: { file },
|
|
30
|
+
});
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const packages = parsed.packages;
|
|
34
|
+
if (!packages)
|
|
35
|
+
continue;
|
|
36
|
+
for (const [name, dep] of Object.entries(packages)) {
|
|
37
|
+
if (!name || name === '')
|
|
38
|
+
continue; // root package
|
|
39
|
+
if (!dep.integrity) {
|
|
40
|
+
ctx.addFinding({
|
|
41
|
+
rule: 'hash-validation',
|
|
42
|
+
severity: 'high',
|
|
43
|
+
message: `Package "${name}" has no integrity hash in lockfile`,
|
|
44
|
+
location: { file },
|
|
45
|
+
suggestion: 'Run npm install to regenerate the lockfile with integrity hashes.',
|
|
46
|
+
metadata: { package: name, version: dep.version },
|
|
47
|
+
});
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (dep.integrity.startsWith('sha1-')) {
|
|
51
|
+
ctx.addFinding({
|
|
52
|
+
rule: 'hash-validation',
|
|
53
|
+
severity: 'medium',
|
|
54
|
+
message: `Package "${name}" uses weak SHA-1 integrity hash`,
|
|
55
|
+
location: { file },
|
|
56
|
+
suggestion: 'Regenerate lockfile to use SHA-512 integrity hashes.',
|
|
57
|
+
metadata: { package: name, version: dep.version },
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=hash-validation.rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash-validation.rule.js","sourceRoot":"","sources":["../../../../src/scanners/dependency-integrity/rules/hash-validation.rule.ts"],"names":[],"mappings":";;;AAAA,+CAA4C;AAC5C,yCAAqC;AAUxB,QAAA,kBAAkB,GAAS;IACtC,EAAE,EAAE,iBAAiB;IACrB,IAAI,EAAE,0BAA0B;IAChC,WAAW,EAAE,gFAAgF;IAE7F,KAAK,CAAC,GAAG,CAAC,GAAgB;QACxB,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,oBAAQ,EAAC,CAAC,CAAC,KAAK,mBAAmB,CAAC,CAAC;QAE/E,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,OAAe,CAAC;YACpB,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,IAAA,mBAAQ,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC1C,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YAED,IAAI,MAAqD,CAAC;YAC1D,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC;YAAC,MAAM,CAAC;gBACP,GAAG,CAAC,UAAU,CAAC;oBACb,IAAI,EAAE,iBAAiB;oBACvB,QAAQ,EAAE,MAAM;oBAChB,OAAO,EAAE,0DAA0D;oBACnE,QAAQ,EAAE,EAAE,IAAI,EAAE;iBACnB,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;YACjC,IAAI,CAAC,QAAQ;gBAAE,SAAS;YAExB,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACnD,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,EAAE;oBAAE,SAAS,CAAC,eAAe;gBAEnD,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;oBACnB,GAAG,CAAC,UAAU,CAAC;wBACb,IAAI,EAAE,iBAAiB;wBACvB,QAAQ,EAAE,MAAM;wBAChB,OAAO,EAAE,YAAY,IAAI,qCAAqC;wBAC9D,QAAQ,EAAE,EAAE,IAAI,EAAE;wBAClB,UAAU,EAAE,mEAAmE;wBAC/E,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE;qBAClD,CAAC,CAAC;oBACH,SAAS;gBACX,CAAC;gBAED,IAAI,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;oBACtC,GAAG,CAAC,UAAU,CAAC;wBACb,IAAI,EAAE,iBAAiB;wBACvB,QAAQ,EAAE,QAAQ;wBAClB,OAAO,EAAE,YAAY,IAAI,kCAAkC;wBAC3D,QAAQ,EAAE,EAAE,IAAI,EAAE;wBAClB,UAAU,EAAE,sDAAsD;wBAClE,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE;qBAClD,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transitive-drift.rule.d.ts","sourceRoot":"","sources":["../../../../src/scanners/dependency-integrity/rules/transitive-drift.rule.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAe,MAAM,yBAAyB,CAAC;AAEjE,eAAO,MAAM,mBAAmB,EAAE,IAkEjC,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.transitiveDriftRule = void 0;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
exports.transitiveDriftRule = {
|
|
7
|
+
id: 'transitive-drift',
|
|
8
|
+
name: 'Transitive Dependency Drift',
|
|
9
|
+
description: 'Detects when package.json and lockfile are out of sync, indicating potential supply chain risk',
|
|
10
|
+
async run(ctx) {
|
|
11
|
+
const packageFiles = ctx.files.filter((f) => (0, node_path_1.basename)(f) === 'package.json');
|
|
12
|
+
for (const pkgFile of packageFiles) {
|
|
13
|
+
const dir = (0, node_path_1.dirname)(pkgFile);
|
|
14
|
+
const lockFile = (0, node_path_1.join)(dir, 'package-lock.json');
|
|
15
|
+
// Check if lockfile exists
|
|
16
|
+
try {
|
|
17
|
+
await (0, promises_1.access)(lockFile);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
ctx.addFinding({
|
|
21
|
+
rule: 'transitive-drift',
|
|
22
|
+
severity: 'medium',
|
|
23
|
+
message: 'No lockfile found alongside package.json',
|
|
24
|
+
location: { file: pkgFile },
|
|
25
|
+
suggestion: 'Run npm install to generate a lockfile. Lockfiles pin transitive dependencies.',
|
|
26
|
+
});
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
let pkgContent;
|
|
30
|
+
let lockContent;
|
|
31
|
+
try {
|
|
32
|
+
pkgContent = await (0, promises_1.readFile)(pkgFile, 'utf-8');
|
|
33
|
+
lockContent = await (0, promises_1.readFile)(lockFile, 'utf-8');
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
let pkg;
|
|
39
|
+
let lock;
|
|
40
|
+
try {
|
|
41
|
+
pkg = JSON.parse(pkgContent);
|
|
42
|
+
lock = JSON.parse(lockContent);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (!lock.packages)
|
|
48
|
+
continue;
|
|
49
|
+
const declared = {
|
|
50
|
+
...pkg.dependencies,
|
|
51
|
+
...pkg.devDependencies,
|
|
52
|
+
};
|
|
53
|
+
for (const [name, range] of Object.entries(declared)) {
|
|
54
|
+
const lockEntry = lock.packages[`node_modules/${name}`];
|
|
55
|
+
if (!lockEntry) {
|
|
56
|
+
ctx.addFinding({
|
|
57
|
+
rule: 'transitive-drift',
|
|
58
|
+
severity: 'high',
|
|
59
|
+
message: `Package "${name}" declared in package.json but missing from lockfile`,
|
|
60
|
+
location: { file: pkgFile },
|
|
61
|
+
suggestion: 'Run npm install to sync the lockfile. Drift creates supply chain risk.',
|
|
62
|
+
metadata: { package: name, declaredRange: range },
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=transitive-drift.rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transitive-drift.rule.js","sourceRoot":"","sources":["../../../../src/scanners/dependency-integrity/rules/transitive-drift.rule.ts"],"names":[],"mappings":";;;AAAA,+CAAoD;AACpD,yCAAoD;AAGvC,QAAA,mBAAmB,GAAS;IACvC,EAAE,EAAE,kBAAkB;IACtB,IAAI,EAAE,6BAA6B;IACnC,WAAW,EAAE,gGAAgG;IAE7G,KAAK,CAAC,GAAG,CAAC,GAAgB;QACxB,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,oBAAQ,EAAC,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC;QAE7E,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;YACnC,MAAM,GAAG,GAAG,IAAA,mBAAO,EAAC,OAAO,CAAC,CAAC;YAC7B,MAAM,QAAQ,GAAG,IAAA,gBAAI,EAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;YAEhD,2BAA2B;YAC3B,IAAI,CAAC;gBACH,MAAM,IAAA,iBAAM,EAAC,QAAQ,CAAC,CAAC;YACzB,CAAC;YAAC,MAAM,CAAC;gBACP,GAAG,CAAC,UAAU,CAAC;oBACb,IAAI,EAAE,kBAAkB;oBACxB,QAAQ,EAAE,QAAQ;oBAClB,OAAO,EAAE,0CAA0C;oBACnD,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;oBAC3B,UAAU,EAAE,gFAAgF;iBAC7F,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YAED,IAAI,UAAkB,CAAC;YACvB,IAAI,WAAmB,CAAC;YACxB,IAAI,CAAC;gBACH,UAAU,GAAG,MAAM,IAAA,mBAAQ,EAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBAC9C,WAAW,GAAG,MAAM,IAAA,mBAAQ,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAClD,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YAED,IAAI,GAAwF,CAAC;YAC7F,IAAI,IAAyD,CAAC;YAC9D,IAAI,CAAC;gBACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBAC7B,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YACjC,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YAED,IAAI,CAAC,IAAI,CAAC,QAAQ;gBAAE,SAAS;YAE7B,MAAM,QAAQ,GAAG;gBACf,GAAG,GAAG,CAAC,YAAY;gBACnB,GAAG,GAAG,CAAC,eAAe;aACvB,CAAC;YAEF,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACrD,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC;gBACxD,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,GAAG,CAAC,UAAU,CAAC;wBACb,IAAI,EAAE,kBAAkB;wBACxB,QAAQ,EAAE,MAAM;wBAChB,OAAO,EAAE,YAAY,IAAI,sDAAsD;wBAC/E,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;wBAC3B,UAAU,EAAE,wEAAwE;wBACpF,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE;qBAClD,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typosquat-check.rule.d.ts","sourceRoot":"","sources":["../../../../src/scanners/dependency-integrity/rules/typosquat-check.rule.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAe,MAAM,yBAAyB,CAAC;AAmCjE,eAAO,MAAM,kBAAkB,EAAE,IA8DhC,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.typosquatCheckRule = void 0;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const known_typosquats_js_1 = require("../patterns/known-typosquats.js");
|
|
7
|
+
function normalize(name) {
|
|
8
|
+
let n = name.toLowerCase();
|
|
9
|
+
for (const [from, to] of known_typosquats_js_1.SUBSTITUTION_PAIRS) {
|
|
10
|
+
n = n.replaceAll(from, to);
|
|
11
|
+
}
|
|
12
|
+
return n;
|
|
13
|
+
}
|
|
14
|
+
function levenshtein(a, b) {
|
|
15
|
+
const m = a.length;
|
|
16
|
+
const n = b.length;
|
|
17
|
+
const dp = Array.from({ length: m + 1 }, (_, i) => Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)));
|
|
18
|
+
for (let i = 1; i <= m; i++) {
|
|
19
|
+
for (let j = 1; j <= n; j++) {
|
|
20
|
+
dp[i][j] = a[i - 1] === b[j - 1]
|
|
21
|
+
? dp[i - 1][j - 1]
|
|
22
|
+
: 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return dp[m][n];
|
|
26
|
+
}
|
|
27
|
+
// Top npm packages to check typosquat distance against
|
|
28
|
+
const POPULAR_PACKAGES = [
|
|
29
|
+
'react', 'express', 'lodash', 'axios', 'next', 'typescript',
|
|
30
|
+
'webpack', 'babel', 'eslint', 'prettier', 'jest', 'vitest',
|
|
31
|
+
'mongoose', 'sequelize', 'prisma', 'stripe', 'nodemailer',
|
|
32
|
+
'dotenv', 'cors', 'bcrypt', 'jsonwebtoken', 'chalk',
|
|
33
|
+
];
|
|
34
|
+
exports.typosquatCheckRule = {
|
|
35
|
+
id: 'typosquat-check',
|
|
36
|
+
name: 'Typosquat Detection',
|
|
37
|
+
description: 'Checks dependencies against known typosquats and fuzzy-matches popular package names',
|
|
38
|
+
async run(ctx) {
|
|
39
|
+
const packageFiles = ctx.files.filter((f) => (0, node_path_1.basename)(f) === 'package.json');
|
|
40
|
+
for (const file of packageFiles) {
|
|
41
|
+
let content;
|
|
42
|
+
try {
|
|
43
|
+
content = await (0, promises_1.readFile)(file, 'utf-8');
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
let parsed;
|
|
49
|
+
try {
|
|
50
|
+
parsed = JSON.parse(content);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const allDeps = [
|
|
56
|
+
...Object.keys(parsed.dependencies ?? {}),
|
|
57
|
+
...Object.keys(parsed.devDependencies ?? {}),
|
|
58
|
+
];
|
|
59
|
+
for (const dep of allDeps) {
|
|
60
|
+
// Check known typosquats
|
|
61
|
+
const knownMatch = known_typosquats_js_1.KNOWN_TYPOSQUATS.find((t) => t.malicious === dep);
|
|
62
|
+
if (knownMatch) {
|
|
63
|
+
ctx.addFinding({
|
|
64
|
+
rule: 'typosquat-check',
|
|
65
|
+
severity: 'critical',
|
|
66
|
+
message: `Known malicious package "${dep}" (typosquat of "${knownMatch.legitimate}")`,
|
|
67
|
+
location: { file },
|
|
68
|
+
suggestion: `Replace with the legitimate package: ${knownMatch.legitimate}`,
|
|
69
|
+
metadata: { technique: knownMatch.technique },
|
|
70
|
+
});
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
// Fuzzy match against popular packages
|
|
74
|
+
const normalized = normalize(dep);
|
|
75
|
+
for (const popular of POPULAR_PACKAGES) {
|
|
76
|
+
if (dep === popular)
|
|
77
|
+
continue;
|
|
78
|
+
const dist = levenshtein(normalized, normalize(popular));
|
|
79
|
+
if (dist === 1) {
|
|
80
|
+
ctx.addFinding({
|
|
81
|
+
rule: 'typosquat-check',
|
|
82
|
+
severity: 'high',
|
|
83
|
+
message: `Package "${dep}" is 1 edit away from popular package "${popular}" — possible typosquat`,
|
|
84
|
+
location: { file },
|
|
85
|
+
suggestion: `Verify this is the intended package, not a typosquat of "${popular}".`,
|
|
86
|
+
metadata: { distance: dist, target: popular },
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=typosquat-check.rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typosquat-check.rule.js","sourceRoot":"","sources":["../../../../src/scanners/dependency-integrity/rules/typosquat-check.rule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../../src/scanners/dependency-integrity/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,sBAAsB,CAAC;AAWvE,eAAO,MAAM,0BAA0B,EAAE,OAaxC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dependencyIntegrityScanner = void 0;
|
|
4
|
+
const hash_validation_rule_js_1 = require("./rules/hash-validation.rule.js");
|
|
5
|
+
const typosquat_check_rule_js_1 = require("./rules/typosquat-check.rule.js");
|
|
6
|
+
const transitive_drift_rule_js_1 = require("./rules/transitive-drift.rule.js");
|
|
7
|
+
const rules = [
|
|
8
|
+
hash_validation_rule_js_1.hashValidationRule,
|
|
9
|
+
typosquat_check_rule_js_1.typosquatCheckRule,
|
|
10
|
+
transitive_drift_rule_js_1.transitiveDriftRule,
|
|
11
|
+
];
|
|
12
|
+
exports.dependencyIntegrityScanner = {
|
|
13
|
+
id: 'dependency-integrity',
|
|
14
|
+
name: 'Dependency Integrity',
|
|
15
|
+
description: 'Validates dependency hashes, detects typosquatting, and flags transitive drift',
|
|
16
|
+
rules,
|
|
17
|
+
async scan(ctx) {
|
|
18
|
+
for (const rule of rules) {
|
|
19
|
+
const ruleConfig = ctx.scannerConfig.rules?.[rule.id];
|
|
20
|
+
if (ruleConfig?.enabled === false)
|
|
21
|
+
continue;
|
|
22
|
+
await rule.run(ctx);
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../../src/scanners/dependency-integrity/scanner.ts"],"names":[],"mappings":";;;AACA,6EAAqE;AACrE,6EAAqE;AACrE,+EAAuE;AAEvE,MAAM,KAAK,GAAW;IACpB,4CAAkB;IAClB,4CAAkB;IAClB,8CAAmB;CACpB,CAAC;AAEW,QAAA,0BAA0B,GAAY;IACjD,EAAE,EAAE,sBAAsB;IAC1B,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EAAE,gFAAgF;IAC7F,KAAK;IAEL,KAAK,CAAC,IAAI,CAAC,GAAgB;QACzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,UAAU,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACtD,IAAI,UAAU,EAAE,OAAO,KAAK,KAAK;gBAAE,SAAS;YAC5C,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scanners/runtime-monitor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runtimeMonitorScanner = void 0;
|
|
4
|
+
var scanner_js_1 = require("./scanner.js");
|
|
5
|
+
Object.defineProperty(exports, "runtimeMonitorScanner", { enumerable: true, get: function () { return scanner_js_1.runtimeMonitorScanner; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/scanners/runtime-monitor/index.ts"],"names":[],"mappings":";;;AAAA,2CAAqD;AAA5C,mHAAA,qBAAqB,OAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface BadDestination {
|
|
2
|
+
pattern: RegExp;
|
|
3
|
+
label: string;
|
|
4
|
+
category: 'c2' | 'exfiltration' | 'cryptominer' | 'suspicious';
|
|
5
|
+
}
|
|
6
|
+
export declare const KNOWN_BAD_DESTINATIONS: BadDestination[];
|
|
7
|
+
export declare const SUSPICIOUS_PORTS: Set<number>;
|
|
8
|
+
//# sourceMappingURL=known-bad-destinations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"known-bad-destinations.d.ts","sourceRoot":"","sources":["../../../../src/scanners/runtime-monitor/patterns/known-bad-destinations.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,IAAI,GAAG,cAAc,GAAG,aAAa,GAAG,YAAY,CAAC;CAChE;AAGD,eAAO,MAAM,sBAAsB,EAAE,cAAc,EAoClD,CAAC;AAGF,eAAO,MAAM,gBAAgB,aAQ3B,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SUSPICIOUS_PORTS = exports.KNOWN_BAD_DESTINATIONS = void 0;
|
|
4
|
+
// Patterns for known malicious or suspicious network destinations
|
|
5
|
+
exports.KNOWN_BAD_DESTINATIONS = [
|
|
6
|
+
{
|
|
7
|
+
pattern: /ngrok\.io/i,
|
|
8
|
+
label: 'ngrok-tunnel',
|
|
9
|
+
category: 'suspicious',
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
pattern: /requestbin\.com|pipedream\.net|webhook\.site|hookbin\.com/i,
|
|
13
|
+
label: 'request-catcher',
|
|
14
|
+
category: 'exfiltration',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
pattern: /pastebin\.com\/api|ghostbin\.com|hastebin\.com/i,
|
|
18
|
+
label: 'paste-service',
|
|
19
|
+
category: 'exfiltration',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
pattern: /coinhive\.min\.js|coin-hive|cryptonight\.wasm/i,
|
|
23
|
+
label: 'cryptominer',
|
|
24
|
+
category: 'cryptominer',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
pattern: /raw\.githubusercontent\.com\/[^/]+\/[^/]+\/[^/]+\/.*\.(sh|ps1|bat|exe)/i,
|
|
28
|
+
label: 'github-raw-script',
|
|
29
|
+
category: 'suspicious',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
pattern: /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{4,5}\b/,
|
|
33
|
+
label: 'raw-ip-with-port',
|
|
34
|
+
category: 'suspicious',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
pattern: /(?:transfer\.sh|file\.io|0x0\.st)\/\w+/i,
|
|
38
|
+
label: 'ephemeral-file-host',
|
|
39
|
+
category: 'exfiltration',
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
// Suspicious outbound ports
|
|
43
|
+
exports.SUSPICIOUS_PORTS = new Set([
|
|
44
|
+
4444, // Metasploit default
|
|
45
|
+
5555, // Common reverse shell
|
|
46
|
+
6666, // IRC / backdoor
|
|
47
|
+
8888, // Alternative HTTP / C2
|
|
48
|
+
9001, // Tor
|
|
49
|
+
9050, // Tor SOCKS
|
|
50
|
+
31337, // Back Orifice
|
|
51
|
+
]);
|
|
52
|
+
//# sourceMappingURL=known-bad-destinations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"known-bad-destinations.js","sourceRoot":"","sources":["../../../../src/scanners/runtime-monitor/patterns/known-bad-destinations.ts"],"names":[],"mappings":";;;AAMA,kEAAkE;AACrD,QAAA,sBAAsB,GAAqB;IACtD;QACE,OAAO,EAAE,YAAY;QACrB,KAAK,EAAE,cAAc;QACrB,QAAQ,EAAE,YAAY;KACvB;IACD;QACE,OAAO,EAAE,4DAA4D;QACrE,KAAK,EAAE,iBAAiB;QACxB,QAAQ,EAAE,cAAc;KACzB;IACD;QACE,OAAO,EAAE,iDAAiD;QAC1D,KAAK,EAAE,eAAe;QACtB,QAAQ,EAAE,cAAc;KACzB;IACD;QACE,OAAO,EAAE,gDAAgD;QACzD,KAAK,EAAE,aAAa;QACpB,QAAQ,EAAE,aAAa;KACxB;IACD;QACE,OAAO,EAAE,yEAAyE;QAClF,KAAK,EAAE,mBAAmB;QAC1B,QAAQ,EAAE,YAAY;KACvB;IACD;QACE,OAAO,EAAE,gDAAgD;QACzD,KAAK,EAAE,kBAAkB;QACzB,QAAQ,EAAE,YAAY;KACvB;IACD;QACE,OAAO,EAAE,yCAAyC;QAClD,KAAK,EAAE,qBAAqB;QAC5B,QAAQ,EAAE,cAAc;KACzB;CACF,CAAC;AAEF,4BAA4B;AACf,QAAA,gBAAgB,GAAG,IAAI,GAAG,CAAC;IACtC,IAAI,EAAG,qBAAqB;IAC5B,IAAI,EAAG,uBAAuB;IAC9B,IAAI,EAAG,iBAAiB;IACxB,IAAI,EAAG,wBAAwB;IAC/B,IAAI,EAAG,MAAM;IACb,IAAI,EAAG,YAAY;IACnB,KAAK,EAAE,eAAe;CACvB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem-access.rule.d.ts","sourceRoot":"","sources":["../../../../src/scanners/runtime-monitor/rules/filesystem-access.rule.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAe,MAAM,yBAAyB,CAAC;AAsBjE,eAAO,MAAM,oBAAoB,EAAE,IAkDlC,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.filesystemAccessRule = void 0;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const CODE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']);
|
|
6
|
+
function isCodeFile(file) {
|
|
7
|
+
const dot = file.lastIndexOf('.');
|
|
8
|
+
return dot !== -1 && CODE_EXTENSIONS.has(file.slice(dot).toLowerCase());
|
|
9
|
+
}
|
|
10
|
+
const SENSITIVE_PATH_PATTERNS = [
|
|
11
|
+
{ pattern: /(?:\/etc\/passwd|\/etc\/shadow|\/etc\/hosts)/g, label: 'system-file' },
|
|
12
|
+
{ pattern: /(?:\.ssh\/|\.gnupg\/|\.aws\/credentials)/g, label: 'credential-file' },
|
|
13
|
+
{ pattern: /(?:\.env(?:\.local)?|\.env\.production)/g, label: 'env-file' },
|
|
14
|
+
{ pattern: /(?:\/proc\/|\/sys\/)/g, label: 'proc-sys' },
|
|
15
|
+
];
|
|
16
|
+
const FS_WITH_USER_INPUT = [
|
|
17
|
+
{ pattern: /(?:readFile|writeFile|readdir|unlink|rmdir)\s*\(\s*(?:req\.|params\.|query\.|body\.|args\.)/g, label: 'user-input-fs' },
|
|
18
|
+
{ pattern: /(?:createReadStream|createWriteStream)\s*\(\s*(?:req\.|params\.|query\.|body\.)/g, label: 'user-input-stream' },
|
|
19
|
+
{ pattern: /path\.join\s*\([^)]*(?:req\.|params\.|query\.|body\.)/g, label: 'user-input-path-join' },
|
|
20
|
+
];
|
|
21
|
+
exports.filesystemAccessRule = {
|
|
22
|
+
id: 'filesystem-access',
|
|
23
|
+
name: 'Filesystem Access Detection',
|
|
24
|
+
description: 'Flags access to sensitive paths and user-controlled filesystem operations',
|
|
25
|
+
async run(ctx) {
|
|
26
|
+
const codeFiles = ctx.files.filter(isCodeFile);
|
|
27
|
+
for (const file of codeFiles) {
|
|
28
|
+
let content;
|
|
29
|
+
try {
|
|
30
|
+
content = await (0, promises_1.readFile)(file, 'utf-8');
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const lines = content.split('\n');
|
|
36
|
+
for (let i = 0; i < lines.length; i++) {
|
|
37
|
+
const line = lines[i];
|
|
38
|
+
for (const { pattern, label } of SENSITIVE_PATH_PATTERNS) {
|
|
39
|
+
pattern.lastIndex = 0;
|
|
40
|
+
if (pattern.test(line)) {
|
|
41
|
+
ctx.addFinding({
|
|
42
|
+
rule: 'filesystem-access',
|
|
43
|
+
severity: label === 'credential-file' ? 'high' : 'medium',
|
|
44
|
+
message: `Access to sensitive path detected: ${label}`,
|
|
45
|
+
location: { file, line: i + 1 },
|
|
46
|
+
evidence: line.trim().slice(0, 200),
|
|
47
|
+
suggestion: 'Review whether this file access is necessary and properly secured.',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
for (const { pattern, label } of FS_WITH_USER_INPUT) {
|
|
52
|
+
pattern.lastIndex = 0;
|
|
53
|
+
if (pattern.test(line)) {
|
|
54
|
+
ctx.addFinding({
|
|
55
|
+
rule: 'filesystem-access',
|
|
56
|
+
severity: 'critical',
|
|
57
|
+
message: `User input flows into filesystem operation: ${label}`,
|
|
58
|
+
location: { file, line: i + 1 },
|
|
59
|
+
evidence: line.trim().slice(0, 200),
|
|
60
|
+
suggestion: 'CRITICAL: Path traversal vulnerability. Validate and sanitize all user-supplied paths.',
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=filesystem-access.rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem-access.rule.js","sourceRoot":"","sources":["../../../../src/scanners/runtime-monitor/rules/filesystem-access.rule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-network.rule.d.ts","sourceRoot":"","sources":["../../../../src/scanners/runtime-monitor/rules/outbound-network.rule.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAe,MAAM,yBAAyB,CAAC;AAYjE,eAAO,MAAM,mBAAmB,EAAE,IAqDjC,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.outboundNetworkRule = void 0;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const known_bad_destinations_js_1 = require("../patterns/known-bad-destinations.js");
|
|
6
|
+
const CODE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']);
|
|
7
|
+
function isCodeFile(file) {
|
|
8
|
+
const dot = file.lastIndexOf('.');
|
|
9
|
+
return dot !== -1 && CODE_EXTENSIONS.has(file.slice(dot).toLowerCase());
|
|
10
|
+
}
|
|
11
|
+
const PORT_PATTERN = /:\s*(\d{4,5})\b/g;
|
|
12
|
+
exports.outboundNetworkRule = {
|
|
13
|
+
id: 'outbound-network',
|
|
14
|
+
name: 'Outbound Network Detection',
|
|
15
|
+
description: 'Flags connections to known malicious destinations and suspicious ports',
|
|
16
|
+
async run(ctx) {
|
|
17
|
+
const codeFiles = ctx.files.filter(isCodeFile);
|
|
18
|
+
for (const file of codeFiles) {
|
|
19
|
+
let content;
|
|
20
|
+
try {
|
|
21
|
+
content = await (0, promises_1.readFile)(file, 'utf-8');
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const lines = content.split('\n');
|
|
27
|
+
for (let i = 0; i < lines.length; i++) {
|
|
28
|
+
const line = lines[i];
|
|
29
|
+
// Check known bad destinations
|
|
30
|
+
for (const dest of known_bad_destinations_js_1.KNOWN_BAD_DESTINATIONS) {
|
|
31
|
+
if (dest.pattern.test(line)) {
|
|
32
|
+
ctx.addFinding({
|
|
33
|
+
rule: 'outbound-network',
|
|
34
|
+
severity: dest.category === 'c2' ? 'critical' : dest.category === 'exfiltration' ? 'high' : 'medium',
|
|
35
|
+
message: `Connection to suspicious destination: ${dest.label} (${dest.category})`,
|
|
36
|
+
location: { file, line: i + 1 },
|
|
37
|
+
evidence: line.trim().slice(0, 200),
|
|
38
|
+
suggestion: 'Review this network destination. It matches a known suspicious pattern.',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Check suspicious ports
|
|
43
|
+
PORT_PATTERN.lastIndex = 0;
|
|
44
|
+
let portMatch;
|
|
45
|
+
while ((portMatch = PORT_PATTERN.exec(line)) !== null) {
|
|
46
|
+
const port = parseInt(portMatch[1], 10);
|
|
47
|
+
if (known_bad_destinations_js_1.SUSPICIOUS_PORTS.has(port)) {
|
|
48
|
+
ctx.addFinding({
|
|
49
|
+
rule: 'outbound-network',
|
|
50
|
+
severity: 'high',
|
|
51
|
+
message: `Connection to suspicious port ${port} — commonly used for ${port === 9001 || port === 9050 ? 'Tor' : 'reverse shells/C2'}`,
|
|
52
|
+
location: { file, line: i + 1 },
|
|
53
|
+
evidence: line.trim().slice(0, 200),
|
|
54
|
+
suggestion: 'This port is associated with malicious tools. Verify this is legitimate.',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=outbound-network.rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-network.rule.js","sourceRoot":"","sources":["../../../../src/scanners/runtime-monitor/rules/outbound-network.rule.ts"],"names":[],"mappings":";;;AAAA,+CAA4C;AAE5C,qFAAiG;AAEjG,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAEhF,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,GAAG,KAAK,CAAC,CAAC,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,YAAY,GAAG,kBAAkB,CAAC;AAE3B,QAAA,mBAAmB,GAAS;IACvC,EAAE,EAAE,kBAAkB;IACtB,IAAI,EAAE,4BAA4B;IAClC,WAAW,EAAE,wEAAwE;IAErF,KAAK,CAAC,GAAG,CAAC,GAAgB;QACxB,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAE/C,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,OAAe,CAAC;YACpB,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,IAAA,mBAAQ,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC1C,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBAEtB,+BAA+B;gBAC/B,KAAK,MAAM,IAAI,IAAI,kDAAsB,EAAE,CAAC;oBAC1C,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC5B,GAAG,CAAC,UAAU,CAAC;4BACb,IAAI,EAAE,kBAAkB;4BACxB,QAAQ,EAAE,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ;4BACpG,OAAO,EAAE,yCAAyC,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,QAAQ,GAAG;4BACjF,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE;4BAC/B,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;4BACnC,UAAU,EAAE,yEAAyE;yBACtF,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;gBAED,yBAAyB;gBACzB,YAAY,CAAC,SAAS,GAAG,CAAC,CAAC;gBAC3B,IAAI,SAAiC,CAAC;gBACtC,OAAO,CAAC,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;oBACtD,MAAM,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBACxC,IAAI,4CAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC/B,GAAG,CAAC,UAAU,CAAC;4BACb,IAAI,EAAE,kBAAkB;4BACxB,QAAQ,EAAE,MAAM;4BAChB,OAAO,EAAE,iCAAiC,IAAI,wBAAwB,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,mBAAmB,EAAE;4BACpI,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE;4BAC/B,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;4BACnC,UAAU,EAAE,0EAA0E;yBACvF,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-spawn.rule.d.ts","sourceRoot":"","sources":["../../../../src/scanners/runtime-monitor/rules/process-spawn.rule.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAe,MAAM,yBAAyB,CAAC;AAkBjE,eAAO,MAAM,gBAAgB,EAAE,IAsC9B,CAAC"}
|