@obfuscan/core 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/LICENSE +201 -0
- package/README.md +224 -0
- package/dist/allowlist.d.ts +25 -0
- package/dist/allowlist.d.ts.map +1 -0
- package/dist/allowlist.js +138 -0
- package/dist/allowlist.js.map +1 -0
- package/dist/detectors/bidi-control.d.ts +14 -0
- package/dist/detectors/bidi-control.d.ts.map +1 -0
- package/dist/detectors/bidi-control.js +67 -0
- package/dist/detectors/bidi-control.js.map +1 -0
- package/dist/detectors/cargo-build-rs-network.d.ts +12 -0
- package/dist/detectors/cargo-build-rs-network.d.ts.map +1 -0
- package/dist/detectors/cargo-build-rs-network.js +54 -0
- package/dist/detectors/cargo-build-rs-network.js.map +1 -0
- package/dist/detectors/decode-then-exec.d.ts +20 -0
- package/dist/detectors/decode-then-exec.d.ts.map +1 -0
- package/dist/detectors/decode-then-exec.js +189 -0
- package/dist/detectors/decode-then-exec.js.map +1 -0
- package/dist/detectors/deserializer-untrusted.d.ts +15 -0
- package/dist/detectors/deserializer-untrusted.d.ts.map +1 -0
- package/dist/detectors/deserializer-untrusted.js +99 -0
- package/dist/detectors/deserializer-untrusted.js.map +1 -0
- package/dist/detectors/dockerfile-curl-pipe-shell.d.ts +10 -0
- package/dist/detectors/dockerfile-curl-pipe-shell.d.ts.map +1 -0
- package/dist/detectors/dockerfile-curl-pipe-shell.js +42 -0
- package/dist/detectors/dockerfile-curl-pipe-shell.js.map +1 -0
- package/dist/detectors/dynamic-exec-non-literal.d.ts +17 -0
- package/dist/detectors/dynamic-exec-non-literal.d.ts.map +1 -0
- package/dist/detectors/dynamic-exec-non-literal.js +104 -0
- package/dist/detectors/dynamic-exec-non-literal.js.map +1 -0
- package/dist/detectors/encoded-array-fingerprint.d.ts +11 -0
- package/dist/detectors/encoded-array-fingerprint.d.ts.map +1 -0
- package/dist/detectors/encoded-array-fingerprint.js +60 -0
- package/dist/detectors/encoded-array-fingerprint.js.map +1 -0
- package/dist/detectors/gha-curl-pipe-shell.d.ts +11 -0
- package/dist/detectors/gha-curl-pipe-shell.d.ts.map +1 -0
- package/dist/detectors/gha-curl-pipe-shell.js +42 -0
- package/dist/detectors/gha-curl-pipe-shell.js.map +1 -0
- package/dist/detectors/high-entropy-literal.d.ts +19 -0
- package/dist/detectors/high-entropy-literal.d.ts.map +1 -0
- package/dist/detectors/high-entropy-literal.js +90 -0
- package/dist/detectors/high-entropy-literal.js.map +1 -0
- package/dist/detectors/homoglyph-identifier.d.ts +16 -0
- package/dist/detectors/homoglyph-identifier.d.ts.map +1 -0
- package/dist/detectors/homoglyph-identifier.js +76 -0
- package/dist/detectors/homoglyph-identifier.js.map +1 -0
- package/dist/detectors/index.d.ts +31 -0
- package/dist/detectors/index.d.ts.map +1 -0
- package/dist/detectors/index.js +60 -0
- package/dist/detectors/index.js.map +1 -0
- package/dist/detectors/library-load-non-literal.d.ts +10 -0
- package/dist/detectors/library-load-non-literal.d.ts.map +1 -0
- package/dist/detectors/library-load-non-literal.js +72 -0
- package/dist/detectors/library-load-non-literal.js.map +1 -0
- package/dist/detectors/long-line.d.ts +12 -0
- package/dist/detectors/long-line.d.ts.map +1 -0
- package/dist/detectors/long-line.js +53 -0
- package/dist/detectors/long-line.js.map +1 -0
- package/dist/detectors/manifest-install-script.d.ts +54 -0
- package/dist/detectors/manifest-install-script.d.ts.map +1 -0
- package/dist/detectors/manifest-install-script.js +272 -0
- package/dist/detectors/manifest-install-script.js.map +1 -0
- package/dist/detectors/network-then-exec.d.ts +17 -0
- package/dist/detectors/network-then-exec.d.ts.map +1 -0
- package/dist/detectors/network-then-exec.js +140 -0
- package/dist/detectors/network-then-exec.js.map +1 -0
- package/dist/detectors/perl-makefile-side-effect.d.ts +17 -0
- package/dist/detectors/perl-makefile-side-effect.d.ts.map +1 -0
- package/dist/detectors/perl-makefile-side-effect.js +72 -0
- package/dist/detectors/perl-makefile-side-effect.js.map +1 -0
- package/dist/detectors/python-setup-side-effect.d.ts +10 -0
- package/dist/detectors/python-setup-side-effect.d.ts.map +1 -0
- package/dist/detectors/python-setup-side-effect.js +87 -0
- package/dist/detectors/python-setup-side-effect.js.map +1 -0
- package/dist/detectors/shell-untrusted-input.d.ts +10 -0
- package/dist/detectors/shell-untrusted-input.d.ts.map +1 -0
- package/dist/detectors/shell-untrusted-input.js +76 -0
- package/dist/detectors/shell-untrusted-input.js.map +1 -0
- package/dist/detectors/string-array-decoder.d.ts +15 -0
- package/dist/detectors/string-array-decoder.d.ts.map +1 -0
- package/dist/detectors/string-array-decoder.js +70 -0
- package/dist/detectors/string-array-decoder.js.map +1 -0
- package/dist/detectors/suspicious-io-cluster.d.ts +11 -0
- package/dist/detectors/suspicious-io-cluster.d.ts.map +1 -0
- package/dist/detectors/suspicious-io-cluster.js +86 -0
- package/dist/detectors/suspicious-io-cluster.js.map +1 -0
- package/dist/diff.d.ts +23 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +144 -0
- package/dist/diff.js.map +1 -0
- package/dist/directives.d.ts +33 -0
- package/dist/directives.d.ts.map +1 -0
- package/dist/directives.js +60 -0
- package/dist/directives.js.map +1 -0
- package/dist/errors.d.ts +19 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +16 -0
- package/dist/errors.js.map +1 -0
- package/dist/grammar/query.d.ts +44 -0
- package/dist/grammar/query.d.ts.map +1 -0
- package/dist/grammar/query.js +24 -0
- package/dist/grammar/query.js.map +1 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +106 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/patterns.d.ts +48 -0
- package/dist/internal/patterns.d.ts.map +1 -0
- package/dist/internal/patterns.js +95 -0
- package/dist/internal/patterns.js.map +1 -0
- package/dist/internal/text.d.ts +14 -0
- package/dist/internal/text.d.ts.map +1 -0
- package/dist/internal/text.js +20 -0
- package/dist/internal/text.js.map +1 -0
- package/dist/rules.d.ts +25 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +195 -0
- package/dist/rules.js.map +1 -0
- package/dist/scan.d.ts +26 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +287 -0
- package/dist/scan.js.map +1 -0
- package/dist/types.d.ts +215 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +50 -0
- package/dist/version.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* obf.library-load-non-literal.<lang> — Layer B.
|
|
3
|
+
*
|
|
4
|
+
* Fires when a dynamic-library-load function (`require`, `importlib.import_module`,
|
|
5
|
+
* `Assembly.Load`, `libloading::Library::new`, …) is called with a non-literal
|
|
6
|
+
* argument.
|
|
7
|
+
*/
|
|
8
|
+
import { lineAtOffset, MAX_FINDINGS_PER_DETECTOR, MAX_SOURCE_BYTES, namedCallAlternation, } from "../internal/patterns.js";
|
|
9
|
+
import { truncateSnippet } from "../internal/text.js";
|
|
10
|
+
const cache = new WeakMap();
|
|
11
|
+
function compile(config) {
|
|
12
|
+
if (cache.has(config))
|
|
13
|
+
return cache.get(config) ?? null;
|
|
14
|
+
const list = config.library_load ?? [];
|
|
15
|
+
if (list.length === 0) {
|
|
16
|
+
cache.set(config, null);
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const re = new RegExp(`(?:^|[^A-Za-z0-9_$])((?:${namedCallAlternation(list)}))\\s*\\(([\\s\\S]{0,12})`, "g");
|
|
20
|
+
cache.set(config, re);
|
|
21
|
+
return re;
|
|
22
|
+
}
|
|
23
|
+
function looksLikeLiteral(peek) {
|
|
24
|
+
const t = peek.replace(/^\s+/, "");
|
|
25
|
+
if (t.length === 0)
|
|
26
|
+
return false;
|
|
27
|
+
const c = t[0];
|
|
28
|
+
return c === '"' || c === "'" || c === "`" && !t.includes("${");
|
|
29
|
+
}
|
|
30
|
+
export const libraryLoadNonLiteral = {
|
|
31
|
+
id: "obf.library-load-non-literal",
|
|
32
|
+
docsUrl: "https://github.com/bytebardorg/obfuscan/blob/main/docs/detectors.md#obflibrary-load-non-literal",
|
|
33
|
+
applies(ctx) {
|
|
34
|
+
return (ctx.config !== null &&
|
|
35
|
+
(ctx.config.library_load?.length ?? 0) > 0 &&
|
|
36
|
+
ctx.source.length > 0 &&
|
|
37
|
+
ctx.source.length < MAX_SOURCE_BYTES);
|
|
38
|
+
},
|
|
39
|
+
run(ctx) {
|
|
40
|
+
if (!ctx.config)
|
|
41
|
+
return [];
|
|
42
|
+
const cfg = ctx.config;
|
|
43
|
+
const re = compile(cfg);
|
|
44
|
+
if (!re)
|
|
45
|
+
return [];
|
|
46
|
+
const findings = [];
|
|
47
|
+
const local = new RegExp(re.source, re.flags);
|
|
48
|
+
let m;
|
|
49
|
+
while ((m = local.exec(ctx.source)) !== null) {
|
|
50
|
+
if (findings.length >= MAX_FINDINGS_PER_DETECTOR)
|
|
51
|
+
break;
|
|
52
|
+
const name = m[1] ?? "";
|
|
53
|
+
const peek = m[2] ?? "";
|
|
54
|
+
if (looksLikeLiteral(peek))
|
|
55
|
+
continue;
|
|
56
|
+
const offset = m.index + (m[0].length - peek.length);
|
|
57
|
+
findings.push({
|
|
58
|
+
ruleId: `obf.library-load-non-literal.${cfg.id}`,
|
|
59
|
+
severity: "warn",
|
|
60
|
+
score: 7,
|
|
61
|
+
file: ctx.path,
|
|
62
|
+
line: lineAtOffset(ctx.source, offset),
|
|
63
|
+
snippet: truncateSnippet(`${name}(${peek}`),
|
|
64
|
+
reason: `Dynamic library load \`${name}\` called with a non-literal argument. ` +
|
|
65
|
+
`Module name flowing from a variable is suspicious.`,
|
|
66
|
+
evidence: { language: cfg.id, loader: name },
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return findings;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=library-load-non-literal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"library-load-non-literal.js","sourceRoot":"","sources":["../../src/detectors/library-load-non-literal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* obf.long-line — Layer A.
|
|
3
|
+
*
|
|
4
|
+
* Flags pathologically long source lines, which are the universal signal
|
|
5
|
+
* of minified or hand-rolled-obfuscated code being slipped into a regular
|
|
6
|
+
* source tree. We don't fire on bona-fide minified bundles — those usually
|
|
7
|
+
* live under `dist/`, `vendor/`, or `node_modules/` and are excluded by
|
|
8
|
+
* convention or allowlist.
|
|
9
|
+
*/
|
|
10
|
+
import type { Detector } from "../types.js";
|
|
11
|
+
export declare const longLine: Detector;
|
|
12
|
+
//# sourceMappingURL=long-line.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"long-line.d.ts","sourceRoot":"","sources":["../../src/detectors/long-line.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAwB,MAAM,aAAa,CAAC;AAOlE,eAAO,MAAM,QAAQ,EAAE,QA0CtB,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* obf.long-line — Layer A.
|
|
3
|
+
*
|
|
4
|
+
* Flags pathologically long source lines, which are the universal signal
|
|
5
|
+
* of minified or hand-rolled-obfuscated code being slipped into a regular
|
|
6
|
+
* source tree. We don't fire on bona-fide minified bundles — those usually
|
|
7
|
+
* live under `dist/`, `vendor/`, or `node_modules/` and are excluded by
|
|
8
|
+
* convention or allowlist.
|
|
9
|
+
*/
|
|
10
|
+
import { MAX_SOURCE_BYTES } from "../internal/patterns.js";
|
|
11
|
+
import { truncateSnippet } from "../internal/text.js";
|
|
12
|
+
const LONG_LINE_THRESHOLD = 2000;
|
|
13
|
+
const VERY_LONG_LINE_THRESHOLD = 10_000;
|
|
14
|
+
export const longLine = {
|
|
15
|
+
id: "obf.long-line",
|
|
16
|
+
docsUrl: "https://github.com/bytebardorg/obfuscan/blob/main/docs/detectors.md#obflong-line",
|
|
17
|
+
applies(ctx) {
|
|
18
|
+
return ctx.source.length > LONG_LINE_THRESHOLD && ctx.source.length < MAX_SOURCE_BYTES;
|
|
19
|
+
},
|
|
20
|
+
run(ctx) {
|
|
21
|
+
const findings = [];
|
|
22
|
+
const src = ctx.source;
|
|
23
|
+
let lineStart = 0;
|
|
24
|
+
let lineNo = 1;
|
|
25
|
+
const len = src.length;
|
|
26
|
+
for (let i = 0; i <= len; i++) {
|
|
27
|
+
if (i === len || src.charCodeAt(i) === 10) {
|
|
28
|
+
const lineLen = i - lineStart;
|
|
29
|
+
if (lineLen >= LONG_LINE_THRESHOLD) {
|
|
30
|
+
const snippet = src.slice(lineStart, lineStart + 200);
|
|
31
|
+
const score = lineLen >= VERY_LONG_LINE_THRESHOLD ? 8 : 5;
|
|
32
|
+
const severity = lineLen >= VERY_LONG_LINE_THRESHOLD ? "warn" : "info";
|
|
33
|
+
findings.push({
|
|
34
|
+
ruleId: longLine.id,
|
|
35
|
+
severity,
|
|
36
|
+
score,
|
|
37
|
+
file: ctx.path,
|
|
38
|
+
line: lineNo,
|
|
39
|
+
snippet: truncateSnippet(snippet),
|
|
40
|
+
reason: `Line ${lineNo} is ${lineLen} characters long. This is the ` +
|
|
41
|
+
`signature of minified or hand-obfuscated code. If the file is ` +
|
|
42
|
+
`intentionally a bundle, suppress with a path allowlist entry.`,
|
|
43
|
+
evidence: { lineLength: lineLen },
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
lineStart = i + 1;
|
|
47
|
+
lineNo++;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return findings;
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=long-line.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"long-line.js","sourceRoot":"","sources":["../../src/detectors/long-line.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,MAAM,mBAAmB,GAAG,IAAI,CAAC;AACjC,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAExC,MAAM,CAAC,MAAM,QAAQ,GAAa;IAChC,EAAE,EAAE,eAAe;IACnB,OAAO,EAAE,kFAAkF;IAE3F,OAAO,CAAC,GAAgB;QACtB,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,mBAAmB,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,gBAAgB,CAAC;IACzF,CAAC;IAED,GAAG,CAAC,GAAgB;QAClB,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC;QACvB,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC;QAEvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;gBAC1C,MAAM,OAAO,GAAG,CAAC,GAAG,SAAS,CAAC;gBAC9B,IAAI,OAAO,IAAI,mBAAmB,EAAE,CAAC;oBACnC,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,SAAS,GAAG,GAAG,CAAC,CAAC;oBACtD,MAAM,KAAK,GAAG,OAAO,IAAI,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC1D,MAAM,QAAQ,GAAG,OAAO,IAAI,wBAAwB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;oBACvE,QAAQ,CAAC,IAAI,CAAC;wBACZ,MAAM,EAAE,QAAQ,CAAC,EAAE;wBACnB,QAAQ;wBACR,KAAK;wBACL,IAAI,EAAE,GAAG,CAAC,IAAI;wBACd,IAAI,EAAE,MAAM;wBACZ,OAAO,EAAE,eAAe,CAAC,OAAO,CAAC;wBACjC,MAAM,EACJ,QAAQ,MAAM,OAAO,OAAO,gCAAgC;4BAC5D,gEAAgE;4BAChE,+DAA+D;wBACjE,QAAQ,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE;qBAClC,CAAC,CAAC;gBACL,CAAC;gBACD,SAAS,GAAG,CAAC,GAAG,CAAC,CAAC;gBAClB,MAAM,EAAE,CAAC;YACX,CAAC;QACH,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* obf.manifest-install-script — install/lifecycle hooks across package manifests.
|
|
3
|
+
*
|
|
4
|
+
* One detector covers every ecosystem whose manifest can run arbitrary code
|
|
5
|
+
* during `install` (or the equivalent dependency-fetch phase). The shape is
|
|
6
|
+
* consistent across ecosystems: a structured manifest declares a script /
|
|
7
|
+
* command / file that the package manager will execute on the consumer's
|
|
8
|
+
* machine when they pull the dependency. That's the supply-chain attack
|
|
9
|
+
* surface; the ecosystem just changes the file format.
|
|
10
|
+
*
|
|
11
|
+
* Coverage:
|
|
12
|
+
*
|
|
13
|
+
* ┌──────────────┬───────────────────────────────┬─────────────────────────┐
|
|
14
|
+
* │ ecosystem │ manifest │ hooks flagged │
|
|
15
|
+
* ├──────────────┼───────────────────────────────┼─────────────────────────┤
|
|
16
|
+
* │ npm/yarn/pnpm│ package.json │ scripts.preinstall, │
|
|
17
|
+
* │ │ │ scripts.install, │
|
|
18
|
+
* │ │ │ scripts.postinstall, │
|
|
19
|
+
* │ │ │ scripts.prepare │
|
|
20
|
+
* │ composer (PHP│ composer.json │ scripts.pre-install-cmd,│
|
|
21
|
+
* │ │ │ scripts.post-install-cmd│
|
|
22
|
+
* │ │ │ scripts.pre-update-cmd, │
|
|
23
|
+
* │ │ │ scripts.post-update-cmd,│
|
|
24
|
+
* │ │ │ scripts.post-autoload- │
|
|
25
|
+
* │ │ │ dump │
|
|
26
|
+
* │ rubygems │ *.gemspec │ extensions = [...] │
|
|
27
|
+
* │ │ │ (extconf.rb / Rakefile│
|
|
28
|
+
* │ │ │ runs at gem install) │
|
|
29
|
+
* │ luarocks │ *.rockspec │ build.type = "command", │
|
|
30
|
+
* │ │ │ build.build_command, │
|
|
31
|
+
* │ │ │ build.install_command │
|
|
32
|
+
* │ nuget │ *.nuspec │ <files src=".../*.ps1"> │
|
|
33
|
+
* │ │ │ for install.ps1 / │
|
|
34
|
+
* │ │ │ init.ps1 │
|
|
35
|
+
* └──────────────┴───────────────────────────────┴─────────────────────────┘
|
|
36
|
+
*
|
|
37
|
+
* Severity:
|
|
38
|
+
* - `warn` (score 6) for any install hook that runs a command on the user's
|
|
39
|
+
* machine. The mere presence of an install hook is not malicious — many
|
|
40
|
+
* legitimate packages ship them — but it is the right line to surface in
|
|
41
|
+
* a code review.
|
|
42
|
+
* - `block` (score 9) when the script body contains exfil-shaped commands:
|
|
43
|
+
* `curl|bash`, `wget ... | sh`, etc. — the shape behind the
|
|
44
|
+
* axios-2026 / chalk+debug-2025 incidents.
|
|
45
|
+
*
|
|
46
|
+
* Evidence:
|
|
47
|
+
* - `manifest`: which ecosystem (`npm`, `composer`, `gemspec`, `rockspec`, `nuspec`)
|
|
48
|
+
* - `hook`: which lifecycle hook fired
|
|
49
|
+
* - `command`: the hook body (truncated in `snippet`)
|
|
50
|
+
* - `curlPipeShell`: boolean — whether the command matched the curl|sh shape
|
|
51
|
+
*/
|
|
52
|
+
import type { Detector } from "../types.js";
|
|
53
|
+
export declare const manifestInstallScript: Detector;
|
|
54
|
+
//# sourceMappingURL=manifest-install-script.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-install-script.d.ts","sourceRoot":"","sources":["../../src/detectors/manifest-install-script.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAwB,MAAM,aAAa,CAAC;AAiPlE,eAAO,MAAM,qBAAqB,EAAE,QAwCnC,CAAC"}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* obf.manifest-install-script — install/lifecycle hooks across package manifests.
|
|
3
|
+
*
|
|
4
|
+
* One detector covers every ecosystem whose manifest can run arbitrary code
|
|
5
|
+
* during `install` (or the equivalent dependency-fetch phase). The shape is
|
|
6
|
+
* consistent across ecosystems: a structured manifest declares a script /
|
|
7
|
+
* command / file that the package manager will execute on the consumer's
|
|
8
|
+
* machine when they pull the dependency. That's the supply-chain attack
|
|
9
|
+
* surface; the ecosystem just changes the file format.
|
|
10
|
+
*
|
|
11
|
+
* Coverage:
|
|
12
|
+
*
|
|
13
|
+
* ┌──────────────┬───────────────────────────────┬─────────────────────────┐
|
|
14
|
+
* │ ecosystem │ manifest │ hooks flagged │
|
|
15
|
+
* ├──────────────┼───────────────────────────────┼─────────────────────────┤
|
|
16
|
+
* │ npm/yarn/pnpm│ package.json │ scripts.preinstall, │
|
|
17
|
+
* │ │ │ scripts.install, │
|
|
18
|
+
* │ │ │ scripts.postinstall, │
|
|
19
|
+
* │ │ │ scripts.prepare │
|
|
20
|
+
* │ composer (PHP│ composer.json │ scripts.pre-install-cmd,│
|
|
21
|
+
* │ │ │ scripts.post-install-cmd│
|
|
22
|
+
* │ │ │ scripts.pre-update-cmd, │
|
|
23
|
+
* │ │ │ scripts.post-update-cmd,│
|
|
24
|
+
* │ │ │ scripts.post-autoload- │
|
|
25
|
+
* │ │ │ dump │
|
|
26
|
+
* │ rubygems │ *.gemspec │ extensions = [...] │
|
|
27
|
+
* │ │ │ (extconf.rb / Rakefile│
|
|
28
|
+
* │ │ │ runs at gem install) │
|
|
29
|
+
* │ luarocks │ *.rockspec │ build.type = "command", │
|
|
30
|
+
* │ │ │ build.build_command, │
|
|
31
|
+
* │ │ │ build.install_command │
|
|
32
|
+
* │ nuget │ *.nuspec │ <files src=".../*.ps1"> │
|
|
33
|
+
* │ │ │ for install.ps1 / │
|
|
34
|
+
* │ │ │ init.ps1 │
|
|
35
|
+
* └──────────────┴───────────────────────────────┴─────────────────────────┘
|
|
36
|
+
*
|
|
37
|
+
* Severity:
|
|
38
|
+
* - `warn` (score 6) for any install hook that runs a command on the user's
|
|
39
|
+
* machine. The mere presence of an install hook is not malicious — many
|
|
40
|
+
* legitimate packages ship them — but it is the right line to surface in
|
|
41
|
+
* a code review.
|
|
42
|
+
* - `block` (score 9) when the script body contains exfil-shaped commands:
|
|
43
|
+
* `curl|bash`, `wget ... | sh`, etc. — the shape behind the
|
|
44
|
+
* axios-2026 / chalk+debug-2025 incidents.
|
|
45
|
+
*
|
|
46
|
+
* Evidence:
|
|
47
|
+
* - `manifest`: which ecosystem (`npm`, `composer`, `gemspec`, `rockspec`, `nuspec`)
|
|
48
|
+
* - `hook`: which lifecycle hook fired
|
|
49
|
+
* - `command`: the hook body (truncated in `snippet`)
|
|
50
|
+
* - `curlPipeShell`: boolean — whether the command matched the curl|sh shape
|
|
51
|
+
*/
|
|
52
|
+
import { truncateSnippet } from "../internal/text.js";
|
|
53
|
+
function classify(p) {
|
|
54
|
+
const norm = p.replace(/\\/g, "/");
|
|
55
|
+
const base = norm.slice(norm.lastIndexOf("/") + 1);
|
|
56
|
+
if (base === "package.json")
|
|
57
|
+
return "npm";
|
|
58
|
+
if (base === "composer.json")
|
|
59
|
+
return "composer";
|
|
60
|
+
if (base.endsWith(".gemspec"))
|
|
61
|
+
return "gemspec";
|
|
62
|
+
if (base.endsWith(".rockspec"))
|
|
63
|
+
return "rockspec";
|
|
64
|
+
if (base.endsWith(".nuspec"))
|
|
65
|
+
return "nuspec";
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
// ─── Severity escalation ────────────────────────────────────────────────────
|
|
69
|
+
const CURL_PIPE_SHELL_RE = /(?:curl|wget|fetch|Invoke-WebRequest|iwr)\b[^\n]{0,300}\|\s*(?:bash|sh|zsh|python|node|perl|powershell|pwsh|iex|Invoke-Expression)/i;
|
|
70
|
+
// PowerShell `iex (New-Object Net.WebClient).DownloadString(...)` — the
|
|
71
|
+
// canonical Windows install-time payload shape, no pipe involved.
|
|
72
|
+
const PS_IEX_DOWNLOAD_RE = /\b(?:iex|Invoke-Expression)\b[^\n]{0,300}\b(?:DownloadString|DownloadFile|Invoke-WebRequest|wget|curl)\b/i;
|
|
73
|
+
function isCurlPipeShape(s) {
|
|
74
|
+
return CURL_PIPE_SHELL_RE.test(s) || PS_IEX_DOWNLOAD_RE.test(s);
|
|
75
|
+
}
|
|
76
|
+
// ─── npm / package.json ─────────────────────────────────────────────────────
|
|
77
|
+
//
|
|
78
|
+
// `prepare` is included because npm runs it on `npm install` from a git URL
|
|
79
|
+
// and on `npm pack` — which is how malicious tarballs are constructed.
|
|
80
|
+
const NPM_INSTALL_HOOKS = ["preinstall", "install", "postinstall", "prepare"];
|
|
81
|
+
function scanNpm(ctx, pkg) {
|
|
82
|
+
if (!pkg.scripts || typeof pkg.scripts !== "object")
|
|
83
|
+
return [];
|
|
84
|
+
const findings = [];
|
|
85
|
+
for (const hook of NPM_INSTALL_HOOKS) {
|
|
86
|
+
const cmd = pkg.scripts[hook];
|
|
87
|
+
if (typeof cmd !== "string" || cmd.length === 0)
|
|
88
|
+
continue;
|
|
89
|
+
findings.push(buildFinding(ctx, "npm", hook, cmd, lineOfJsonKey(ctx.source, hook)));
|
|
90
|
+
}
|
|
91
|
+
return findings;
|
|
92
|
+
}
|
|
93
|
+
// ─── composer / composer.json ───────────────────────────────────────────────
|
|
94
|
+
const COMPOSER_INSTALL_HOOKS = [
|
|
95
|
+
"pre-install-cmd",
|
|
96
|
+
"post-install-cmd",
|
|
97
|
+
"pre-update-cmd",
|
|
98
|
+
"post-update-cmd",
|
|
99
|
+
"post-autoload-dump",
|
|
100
|
+
];
|
|
101
|
+
function scanComposer(ctx, pkg) {
|
|
102
|
+
if (!pkg.scripts || typeof pkg.scripts !== "object")
|
|
103
|
+
return [];
|
|
104
|
+
const findings = [];
|
|
105
|
+
for (const hook of COMPOSER_INSTALL_HOOKS) {
|
|
106
|
+
const raw = pkg.scripts[hook];
|
|
107
|
+
if (raw == null)
|
|
108
|
+
continue;
|
|
109
|
+
const cmds = Array.isArray(raw) ? raw : [raw];
|
|
110
|
+
for (const cmd of cmds) {
|
|
111
|
+
if (typeof cmd !== "string" || cmd.length === 0)
|
|
112
|
+
continue;
|
|
113
|
+
findings.push(buildFinding(ctx, "composer", hook, cmd, lineOfJsonKey(ctx.source, hook)));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return findings;
|
|
117
|
+
}
|
|
118
|
+
// ─── rubygems / *.gemspec ───────────────────────────────────────────────────
|
|
119
|
+
//
|
|
120
|
+
// Gemspecs are Ruby, not JSON. We don't need a Ruby parser — `extensions` is
|
|
121
|
+
// almost always assigned via a literal array of relative paths. Anything
|
|
122
|
+
// non-trivial is itself worth surfacing.
|
|
123
|
+
const GEMSPEC_EXTENSIONS_RE = /\b\w+\.extensions\s*(?:=|<<)\s*(\[[^\]]*\]|%w[\[\(][^\]\)]*[\]\)]|['"][^'"]+['"])/;
|
|
124
|
+
function scanGemspec(ctx) {
|
|
125
|
+
const m = GEMSPEC_EXTENSIONS_RE.exec(ctx.source);
|
|
126
|
+
if (!m)
|
|
127
|
+
return [];
|
|
128
|
+
const value = m[1] ?? "";
|
|
129
|
+
return [buildFinding(ctx, "gemspec", "extensions", value, lineAt(ctx.source, m.index))];
|
|
130
|
+
}
|
|
131
|
+
// ─── luarocks / *.rockspec ──────────────────────────────────────────────────
|
|
132
|
+
//
|
|
133
|
+
// Rockspec is Lua data; the install-time hook is the `build` table. We grep
|
|
134
|
+
// for the high-risk shapes: build.type == "command" or any *_command field.
|
|
135
|
+
const ROCKSPEC_BUILD_TYPE_RE = /build\s*=\s*\{[^}]*?type\s*=\s*['"]command['"]/s;
|
|
136
|
+
const ROCKSPEC_COMMAND_FIELD_RE = /(\bbuild_command\b|\binstall_command\b|\bcommand\b)\s*=\s*['"]([^'"\n]{1,400})['"]/;
|
|
137
|
+
function scanRockspec(ctx) {
|
|
138
|
+
const findings = [];
|
|
139
|
+
const declaresCommand = ROCKSPEC_BUILD_TYPE_RE.test(ctx.source);
|
|
140
|
+
const cmd = ROCKSPEC_COMMAND_FIELD_RE.exec(ctx.source);
|
|
141
|
+
if (declaresCommand) {
|
|
142
|
+
const where = ctx.source.search(ROCKSPEC_BUILD_TYPE_RE);
|
|
143
|
+
findings.push(buildFinding(ctx, "rockspec", "build.type", "command", where >= 0 ? lineAt(ctx.source, where) : 1));
|
|
144
|
+
}
|
|
145
|
+
if (cmd) {
|
|
146
|
+
const field = cmd[1] ?? "command";
|
|
147
|
+
const value = cmd[2] ?? "";
|
|
148
|
+
findings.push(buildFinding(ctx, "rockspec", field, value, lineAt(ctx.source, cmd.index)));
|
|
149
|
+
}
|
|
150
|
+
return findings;
|
|
151
|
+
}
|
|
152
|
+
// ─── nuget / *.nuspec ───────────────────────────────────────────────────────
|
|
153
|
+
//
|
|
154
|
+
// .nuspec is XML. NuGet historically auto-ran `tools/install.ps1`,
|
|
155
|
+
// `tools/init.ps1`, `tools/uninstall.ps1` at package install. Those files are
|
|
156
|
+
// auto-discovered by path; the .nuspec is the place we can see *that they
|
|
157
|
+
// exist* without the rest of the package tree, because they're declared in
|
|
158
|
+
// `<files>` entries. We also surface direct PowerShell content inlined into
|
|
159
|
+
// the manifest.
|
|
160
|
+
// Matches the inner `<file src="tools/install.ps1" .../>` entry as well as a
|
|
161
|
+
// degenerate `<files src="...install.ps1" .../>` shorthand. NuGet historically
|
|
162
|
+
// auto-ran any tools/{install,init,uninstall}.ps1 inside the package.
|
|
163
|
+
const NUSPEC_FILES_PS1_RE = /<files?\b[^>]*\bsrc\s*=\s*['"]([^'"]*\b(?:install|init|uninstall)\.ps1)['"]/gi;
|
|
164
|
+
function scanNuspec(ctx) {
|
|
165
|
+
const findings = [];
|
|
166
|
+
let m;
|
|
167
|
+
NUSPEC_FILES_PS1_RE.lastIndex = 0;
|
|
168
|
+
while ((m = NUSPEC_FILES_PS1_RE.exec(ctx.source)) !== null) {
|
|
169
|
+
const ref = m[1] ?? "";
|
|
170
|
+
findings.push(buildFinding(ctx, "nuspec", "files.install-ps1", ref, lineAt(ctx.source, m.index)));
|
|
171
|
+
}
|
|
172
|
+
return findings;
|
|
173
|
+
}
|
|
174
|
+
// ─── Finding builder ────────────────────────────────────────────────────────
|
|
175
|
+
function buildFinding(ctx, manifest, hook, command, line) {
|
|
176
|
+
const escalated = isCurlPipeShape(command);
|
|
177
|
+
return {
|
|
178
|
+
ruleId: "obf.manifest-install-script",
|
|
179
|
+
severity: escalated ? "block" : "warn",
|
|
180
|
+
score: escalated ? 9 : 6,
|
|
181
|
+
file: ctx.path,
|
|
182
|
+
line,
|
|
183
|
+
snippet: truncateSnippet(`${manifest}:${hook} ${command}`),
|
|
184
|
+
reason: escalated
|
|
185
|
+
? reasonEscalated(manifest, hook)
|
|
186
|
+
: reasonBase(manifest, hook),
|
|
187
|
+
evidence: { manifest, hook, command, curlPipeShell: escalated },
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function reasonBase(manifest, hook) {
|
|
191
|
+
switch (manifest) {
|
|
192
|
+
case "npm":
|
|
193
|
+
return (`npm \`${hook}\` lifecycle script runs automatically on \`npm install\`. ` +
|
|
194
|
+
`Review for network calls, decoders, or shell-exec patterns.`);
|
|
195
|
+
case "composer":
|
|
196
|
+
return (`Composer \`${hook}\` script runs during \`composer install\`/\`update\`. ` +
|
|
197
|
+
`Review for network calls, decoders, or shell-exec patterns.`);
|
|
198
|
+
case "gemspec":
|
|
199
|
+
return (`Gemspec declares native extensions; \`gem install\` will execute the ` +
|
|
200
|
+
`referenced \`extconf.rb\` / \`Rakefile\` on the user's machine.`);
|
|
201
|
+
case "rockspec":
|
|
202
|
+
return (`Rockspec declares a \`${hook}\` build hook; \`luarocks install\` will ` +
|
|
203
|
+
`run this command on the user's machine.`);
|
|
204
|
+
case "nuspec":
|
|
205
|
+
return (`.nuspec ships an auto-run PowerShell file (\`${hook}\`); legacy NuGet ` +
|
|
206
|
+
`clients execute these on package install.`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function reasonEscalated(manifest, hook) {
|
|
210
|
+
return (`${manifest} \`${hook}\` hook pipes a network download into a shell. This ` +
|
|
211
|
+
`is the exfil/payload-delivery shape behind the axios-2026 / ` +
|
|
212
|
+
`chalk+debug-2025 supply-chain incidents.`);
|
|
213
|
+
}
|
|
214
|
+
// ─── Source helpers ─────────────────────────────────────────────────────────
|
|
215
|
+
function lineOfJsonKey(source, key) {
|
|
216
|
+
const re = new RegExp(`"${key.replace(/[.*+?^${}()|[\]\\-]/g, "\\$&")}"\\s*:`, "g");
|
|
217
|
+
const m = re.exec(source);
|
|
218
|
+
if (!m)
|
|
219
|
+
return 1;
|
|
220
|
+
return lineAt(source, m.index);
|
|
221
|
+
}
|
|
222
|
+
function lineAt(source, offset) {
|
|
223
|
+
let line = 1;
|
|
224
|
+
const stop = Math.min(offset, source.length);
|
|
225
|
+
for (let i = 0; i < stop; i++) {
|
|
226
|
+
if (source.charCodeAt(i) === 10)
|
|
227
|
+
line++;
|
|
228
|
+
}
|
|
229
|
+
return line;
|
|
230
|
+
}
|
|
231
|
+
// ─── Public detector ────────────────────────────────────────────────────────
|
|
232
|
+
export const manifestInstallScript = {
|
|
233
|
+
id: "obf.manifest-install-script",
|
|
234
|
+
docsUrl: "https://github.com/bytebardorg/obfuscan/blob/main/docs/detectors.md#obfmanifest-install-script",
|
|
235
|
+
applies(ctx) {
|
|
236
|
+
return classify(ctx.path) !== null;
|
|
237
|
+
},
|
|
238
|
+
run(ctx) {
|
|
239
|
+
const kind = classify(ctx.path);
|
|
240
|
+
if (kind === null)
|
|
241
|
+
return [];
|
|
242
|
+
switch (kind) {
|
|
243
|
+
case "npm": {
|
|
244
|
+
let pkg;
|
|
245
|
+
try {
|
|
246
|
+
pkg = JSON.parse(ctx.source);
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
return [];
|
|
250
|
+
}
|
|
251
|
+
return scanNpm(ctx, pkg);
|
|
252
|
+
}
|
|
253
|
+
case "composer": {
|
|
254
|
+
let pkg;
|
|
255
|
+
try {
|
|
256
|
+
pkg = JSON.parse(ctx.source);
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
return [];
|
|
260
|
+
}
|
|
261
|
+
return scanComposer(ctx, pkg);
|
|
262
|
+
}
|
|
263
|
+
case "gemspec":
|
|
264
|
+
return scanGemspec(ctx);
|
|
265
|
+
case "rockspec":
|
|
266
|
+
return scanRockspec(ctx);
|
|
267
|
+
case "nuspec":
|
|
268
|
+
return scanNuspec(ctx);
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
//# sourceMappingURL=manifest-install-script.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-install-script.js","sourceRoot":"","sources":["../../src/detectors/manifest-install-script.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* obf.network-then-exec.<lang> — Layer B.
|
|
3
|
+
*
|
|
4
|
+
* Fires when network IO output flows into a dynamic-exec sink. The shape:
|
|
5
|
+
*
|
|
6
|
+
* eval(await (await fetch(url)).text())
|
|
7
|
+
* exec(requests.get(url).text)
|
|
8
|
+
* IEX (New-Object Net.WebClient).DownloadString($u)
|
|
9
|
+
* eval "$(curl -s $URL)"
|
|
10
|
+
*
|
|
11
|
+
* Unlike decode-then-exec, the source of the executed string is *external*
|
|
12
|
+
* — strictly worse, because the attacker doesn't even need to be in the
|
|
13
|
+
* source tree. Always blocks.
|
|
14
|
+
*/
|
|
15
|
+
import type { Detector } from "../types.js";
|
|
16
|
+
export declare const networkThenExec: Detector;
|
|
17
|
+
//# sourceMappingURL=network-then-exec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-then-exec.d.ts","sourceRoot":"","sources":["../../src/detectors/network-then-exec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAwC,MAAM,aAAa,CAAC;AAyFlF,eAAO,MAAM,eAAe,EAAE,QAiD7B,CAAC"}
|