@cdxgen/cdxgen 13.4.0 → 13.6.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.
Files changed (305) hide show
  1. package/README.md +9 -9
  2. package/bin/cdxgen-secure.js +15 -0
  3. package/bin/cdxgen.js +29 -5
  4. package/bin/evinse.js +8 -0
  5. package/bin/hbom.js +15 -7
  6. package/bin/repl.js +29 -0
  7. package/bin/validate.js +6 -0
  8. package/data/cbomosdb-queries.json +13 -1
  9. package/data/component-tags.json +8 -0
  10. package/data/license-aliases.json +24 -2
  11. package/data/queries-darwin.json +25 -1
  12. package/data/queries-win.json +19 -1
  13. package/data/queries.json +41 -0
  14. package/data/remediations.json +407 -1
  15. package/data/rules/ai-bom.yaml +1 -1
  16. package/data/rules/brotli-decoder.yaml +107 -0
  17. package/data/rules/cbom-security.yaml +235 -4
  18. package/data/rules/go-binaries.yaml +46 -0
  19. package/data/rules/golem-go.yaml +80 -0
  20. package/data/rules/hbom-compliance.yaml +40 -22
  21. package/data/rules/hbom-performance.yaml +7 -1
  22. package/data/rules/host-topology.yaml +1 -1
  23. package/data/rules/obom-runtime.yaml +31 -2
  24. package/data/rules/php-runtime.yaml +143 -0
  25. package/data/rules/vscode-extensions.yaml +75 -0
  26. package/data/spdx-license-list.json +121 -7
  27. package/data/spdx-licenses.json +69 -0
  28. package/data/spdx.schema.json +845 -2
  29. package/lib/audit/index.js +14 -0
  30. package/lib/cli/bomAssembly.js +120 -6
  31. package/lib/cli/cliOptions.js +110 -3
  32. package/lib/cli/index.js +182 -6
  33. package/lib/cli/jsBom.js +153 -64
  34. package/lib/cli/jvmBom.js +363 -66
  35. package/lib/cli/managedBom.js +853 -87
  36. package/lib/cli/nativeBom.js +267 -33
  37. package/lib/core/boundedFile.js +344 -0
  38. package/lib/core/brotliProbe.js +182 -0
  39. package/lib/core/env.js +38 -8
  40. package/lib/core/fs.js +40 -19
  41. package/lib/core/httpClient.js +172 -46
  42. package/lib/core/lockPaths.js +38 -0
  43. package/lib/core/paths.js +24 -1
  44. package/lib/core/processTree.js +5 -0
  45. package/lib/core/projectConfig.js +1 -0
  46. package/lib/core/projectTooling.js +97 -0
  47. package/lib/core/propertySanitizer.js +72 -0
  48. package/lib/core/toolRegistry.js +170 -0
  49. package/lib/ecosystems/cppEvidence.js +263 -106
  50. package/lib/ecosystems/cppIncludeResolver.js +16 -5
  51. package/lib/ecosystems/ecosystems.js +25 -10
  52. package/lib/ecosystems/gemHostProbe.js +301 -0
  53. package/lib/ecosystems/golem.js +550 -6
  54. package/lib/ecosystems/gradleutils.js +858 -244
  55. package/lib/ecosystems/parsers-bazel.js +107 -6
  56. package/lib/ecosystems/parsers-dotnet.js +117 -18
  57. package/lib/ecosystems/parsers-go.js +1090 -367
  58. package/lib/ecosystems/parsers-js.js +505 -22
  59. package/lib/ecosystems/parsers-jvm.js +259 -17
  60. package/lib/ecosystems/parsers-misc.js +438 -64
  61. package/lib/ecosystems/parsers-python.js +100 -12
  62. package/lib/ecosystems/pythonutils.js +128 -2
  63. package/lib/ecosystems/rubyutils.js +544 -34
  64. package/lib/ecosystems/rusi.js +10 -0
  65. package/lib/ecosystems/scalacliutils.js +4 -1
  66. package/lib/ecosystems/scalasem.js +798 -151
  67. package/lib/ecosystems/vendoredCode.js +237 -3
  68. package/lib/ecosystems/venvProbe.js +360 -0
  69. package/lib/evinser/evinser.js +472 -61
  70. package/lib/evinser/swiftsem.js +68 -5
  71. package/lib/helpers/agenticToolutils.js +413 -93
  72. package/lib/helpers/vsixutils.js +1574 -315
  73. package/lib/inventory/agentSkillSpec.js +17 -0
  74. package/lib/inventory/apkInstalledDb.js +243 -0
  75. package/lib/inventory/atomUtils.js +110 -0
  76. package/lib/inventory/auditCategories.js +3 -3
  77. package/lib/inventory/brotliDecoder.js +142 -0
  78. package/lib/inventory/buildToolRateLimit.js +1 -1
  79. package/lib/inventory/cacheDir.js +52 -9
  80. package/lib/inventory/cbomutils.js +56 -7
  81. package/lib/inventory/certificates.js +2371 -0
  82. package/lib/inventory/communityAiConfigParser.js +4 -9
  83. package/lib/inventory/deps.js +41 -4
  84. package/lib/inventory/display.js +200 -3
  85. package/lib/inventory/dosai.js +639 -63
  86. package/lib/inventory/dotnetRuntime.js +217 -0
  87. package/lib/inventory/dynamic.js +45 -3
  88. package/lib/inventory/envcontext.js +475 -18
  89. package/lib/inventory/evidenceUtils.js +447 -23
  90. package/lib/inventory/fetchBatch.js +1 -1
  91. package/lib/inventory/formulationParsers.js +32 -3
  92. package/lib/inventory/goBuildInfo.js +140 -0
  93. package/lib/inventory/gtfobins.js +13 -0
  94. package/lib/inventory/hbom.js +67 -7
  95. package/lib/inventory/hbomAnalysis.js +16 -0
  96. package/lib/inventory/hostRuntimeProbe.js +686 -0
  97. package/lib/inventory/hostTopology.js +21 -0
  98. package/lib/inventory/jvmLocalRepos.js +9 -2
  99. package/lib/inventory/jvmToolEnv.js +29 -0
  100. package/lib/inventory/licenseEnhancer.js +12 -0
  101. package/lib/inventory/mavenCentralMirror.js +534 -0
  102. package/lib/inventory/nodeBuildInfo.js +218 -0
  103. package/lib/inventory/nodeHostProbe.js +202 -0
  104. package/lib/inventory/osPackagePurl.js +244 -0
  105. package/lib/inventory/osPackageResolver.js +271 -87
  106. package/lib/inventory/osinfo.js +79 -31
  107. package/lib/inventory/osqueryTransform.js +114 -5
  108. package/lib/inventory/phpBuildInfo.js +438 -0
  109. package/lib/inventory/phpHostProbe.js +185 -0
  110. package/lib/inventory/rootfsCerts.js +426 -0
  111. package/lib/inventory/rubyBuildInfo.js +972 -0
  112. package/lib/inventory/rubyHostProbe.js +218 -0
  113. package/lib/inventory/scalaCoords.js +4 -3
  114. package/lib/inventory/scalaDedupe.js +440 -0
  115. package/lib/inventory/source.js +256 -5
  116. package/lib/inventory/spdx.js +144 -0
  117. package/lib/inventory/traceRunner.js +5 -1
  118. package/lib/inventory/tracedCrypto.js +129 -0
  119. package/lib/managers/binary.js +866 -186
  120. package/lib/managers/docker.js +245 -12
  121. package/lib/parsers/email.js +277 -0
  122. package/lib/parsers/largeJson.js +62 -13
  123. package/lib/parsers/vscodeExtensionId.js +183 -0
  124. package/lib/server/server.js +198 -2
  125. package/lib/stages/postgen/annotator.js +17 -1
  126. package/lib/stages/postgen/introspection/reflect.js +4 -1
  127. package/lib/stages/postgen/postgen.js +5 -5
  128. package/lib/stages/postgen/ruleEngine.js +71 -6
  129. package/lib/stages/postgen/specVersionCompat.js +30 -0
  130. package/lib/stages/pregen/envAudit.js +1 -0
  131. package/lib/stages/pregen/pregen.js +231 -62
  132. package/lib/validator/bomValidator.js +32 -6
  133. package/lib/validator/generated/runtime.mjs +13 -0
  134. package/lib/validator/generated/validate-1.6.mjs +27 -8
  135. package/lib/validator/generated/validate-1.7.mjs +32 -13
  136. package/lib/validator/generated/validate-2.0.mjs +31 -12
  137. package/lib/validator/index.js +1 -1
  138. package/package.json +19 -18
  139. package/types/bin/cdxgen-secure.d.ts +3 -0
  140. package/types/bin/cdxgen-secure.d.ts.map +1 -0
  141. package/types/bin/repl.d.ts.map +1 -1
  142. package/types/lib/audit/index.d.ts.map +1 -1
  143. package/types/lib/cli/bomAssembly.d.ts +22 -3
  144. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  145. package/types/lib/cli/cliOptions.d.ts +43 -0
  146. package/types/lib/cli/cliOptions.d.ts.map +1 -1
  147. package/types/lib/cli/index.d.ts.map +1 -1
  148. package/types/lib/cli/jsBom.d.ts +1 -17
  149. package/types/lib/cli/jsBom.d.ts.map +1 -1
  150. package/types/lib/cli/jvmBom.d.ts +20 -0
  151. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  152. package/types/lib/cli/managedBom.d.ts.map +1 -1
  153. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  154. package/types/lib/core/boundedFile.d.ts +70 -0
  155. package/types/lib/core/boundedFile.d.ts.map +1 -0
  156. package/types/lib/core/brotliProbe.d.ts +37 -0
  157. package/types/lib/core/brotliProbe.d.ts.map +1 -0
  158. package/types/lib/core/env.d.ts +22 -2
  159. package/types/lib/core/env.d.ts.map +1 -1
  160. package/types/lib/core/fs.d.ts.map +1 -1
  161. package/types/lib/core/httpClient.d.ts +24 -0
  162. package/types/lib/core/httpClient.d.ts.map +1 -1
  163. package/types/lib/core/lockPaths.d.ts +19 -0
  164. package/types/lib/core/lockPaths.d.ts.map +1 -0
  165. package/types/lib/core/processTree.d.ts +2 -0
  166. package/types/lib/core/processTree.d.ts.map +1 -1
  167. package/types/lib/core/projectConfig.d.ts.map +1 -1
  168. package/types/lib/core/projectTooling.d.ts +41 -0
  169. package/types/lib/core/projectTooling.d.ts.map +1 -0
  170. package/types/lib/core/propertySanitizer.d.ts +26 -0
  171. package/types/lib/core/propertySanitizer.d.ts.map +1 -1
  172. package/types/lib/core/toolRegistry.d.ts +36 -0
  173. package/types/lib/core/toolRegistry.d.ts.map +1 -0
  174. package/types/lib/ecosystems/cppEvidence.d.ts +40 -13
  175. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
  176. package/types/lib/ecosystems/cppIncludeResolver.d.ts +2 -1
  177. package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -1
  178. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  179. package/types/lib/ecosystems/gemHostProbe.d.ts +28 -0
  180. package/types/lib/ecosystems/gemHostProbe.d.ts.map +1 -0
  181. package/types/lib/ecosystems/golem.d.ts +81 -1
  182. package/types/lib/ecosystems/golem.d.ts.map +1 -1
  183. package/types/lib/ecosystems/gradleutils.d.ts +57 -21
  184. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  185. package/types/lib/ecosystems/parsers-bazel.d.ts.map +1 -1
  186. package/types/lib/ecosystems/parsers-dotnet.d.ts +40 -4
  187. package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
  188. package/types/lib/ecosystems/parsers-go.d.ts +85 -13
  189. package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
  190. package/types/lib/ecosystems/parsers-js.d.ts +17 -20
  191. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  192. package/types/lib/ecosystems/parsers-jvm.d.ts +28 -2
  193. package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
  194. package/types/lib/ecosystems/parsers-misc.d.ts +37 -58
  195. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  196. package/types/lib/ecosystems/parsers-python.d.ts +14 -3
  197. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  198. package/types/lib/ecosystems/pythonutils.d.ts +19 -1
  199. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
  200. package/types/lib/ecosystems/rubyutils.d.ts +144 -12
  201. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  202. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  203. package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -1
  204. package/types/lib/ecosystems/scalasem.d.ts.map +1 -1
  205. package/types/lib/ecosystems/vendoredCode.d.ts +26 -0
  206. package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -1
  207. package/types/lib/ecosystems/venvProbe.d.ts +40 -0
  208. package/types/lib/ecosystems/venvProbe.d.ts.map +1 -0
  209. package/types/lib/evinser/evinser.d.ts +88 -8
  210. package/types/lib/evinser/evinser.d.ts.map +1 -1
  211. package/types/lib/evinser/swiftsem.d.ts +10 -0
  212. package/types/lib/evinser/swiftsem.d.ts.map +1 -1
  213. package/types/lib/inventory/agentSkillSpec.d.ts +13 -0
  214. package/types/lib/inventory/agentSkillSpec.d.ts.map +1 -0
  215. package/types/lib/inventory/apkInstalledDb.d.ts +42 -0
  216. package/types/lib/inventory/apkInstalledDb.d.ts.map +1 -0
  217. package/types/lib/inventory/atomUtils.d.ts +33 -0
  218. package/types/lib/inventory/atomUtils.d.ts.map +1 -1
  219. package/types/lib/inventory/brotliDecoder.d.ts +58 -0
  220. package/types/lib/inventory/brotliDecoder.d.ts.map +1 -0
  221. package/types/lib/inventory/cacheDir.d.ts +12 -4
  222. package/types/lib/inventory/cacheDir.d.ts.map +1 -1
  223. package/types/lib/inventory/cbomutils.d.ts +17 -0
  224. package/types/lib/inventory/cbomutils.d.ts.map +1 -1
  225. package/types/lib/inventory/certificates.d.ts +205 -0
  226. package/types/lib/inventory/certificates.d.ts.map +1 -0
  227. package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
  228. package/types/lib/inventory/deps.d.ts +2 -1
  229. package/types/lib/inventory/deps.d.ts.map +1 -1
  230. package/types/lib/inventory/display.d.ts +18 -0
  231. package/types/lib/inventory/display.d.ts.map +1 -1
  232. package/types/lib/inventory/dosai.d.ts +162 -7
  233. package/types/lib/inventory/dosai.d.ts.map +1 -1
  234. package/types/lib/inventory/dotnetRuntime.d.ts +44 -0
  235. package/types/lib/inventory/dotnetRuntime.d.ts.map +1 -0
  236. package/types/lib/inventory/dynamic.d.ts +6 -1
  237. package/types/lib/inventory/dynamic.d.ts.map +1 -1
  238. package/types/lib/inventory/envcontext.d.ts +92 -8
  239. package/types/lib/inventory/envcontext.d.ts.map +1 -1
  240. package/types/lib/inventory/evidenceUtils.d.ts +29 -10
  241. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  242. package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
  243. package/types/lib/inventory/goBuildInfo.d.ts +10 -0
  244. package/types/lib/inventory/goBuildInfo.d.ts.map +1 -0
  245. package/types/lib/inventory/gtfobins.d.ts.map +1 -1
  246. package/types/lib/inventory/hbom.d.ts.map +1 -1
  247. package/types/lib/inventory/hbomAnalysis.d.ts +10 -0
  248. package/types/lib/inventory/hbomAnalysis.d.ts.map +1 -1
  249. package/types/lib/inventory/hostRuntimeProbe.d.ts +44 -0
  250. package/types/lib/inventory/hostRuntimeProbe.d.ts.map +1 -0
  251. package/types/lib/inventory/hostTopology.d.ts.map +1 -1
  252. package/types/lib/inventory/jvmToolEnv.d.ts +12 -0
  253. package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -1
  254. package/types/lib/inventory/licenseEnhancer.d.ts.map +1 -1
  255. package/types/lib/inventory/mavenCentralMirror.d.ts +170 -0
  256. package/types/lib/inventory/mavenCentralMirror.d.ts.map +1 -0
  257. package/types/lib/inventory/nodeBuildInfo.d.ts +95 -0
  258. package/types/lib/inventory/nodeBuildInfo.d.ts.map +1 -0
  259. package/types/lib/inventory/nodeHostProbe.d.ts +15 -0
  260. package/types/lib/inventory/nodeHostProbe.d.ts.map +1 -0
  261. package/types/lib/inventory/osPackagePurl.d.ts +99 -0
  262. package/types/lib/inventory/osPackagePurl.d.ts.map +1 -0
  263. package/types/lib/inventory/osPackageResolver.d.ts +44 -2
  264. package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
  265. package/types/lib/inventory/osinfo.d.ts +31 -6
  266. package/types/lib/inventory/osinfo.d.ts.map +1 -1
  267. package/types/lib/inventory/osqueryTransform.d.ts +51 -0
  268. package/types/lib/inventory/osqueryTransform.d.ts.map +1 -1
  269. package/types/lib/inventory/phpBuildInfo.d.ts +142 -0
  270. package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -0
  271. package/types/lib/inventory/phpHostProbe.d.ts +35 -0
  272. package/types/lib/inventory/phpHostProbe.d.ts.map +1 -0
  273. package/types/lib/inventory/rootfsCerts.d.ts +27 -0
  274. package/types/lib/inventory/rootfsCerts.d.ts.map +1 -0
  275. package/types/lib/inventory/rubyBuildInfo.d.ts +271 -0
  276. package/types/lib/inventory/rubyBuildInfo.d.ts.map +1 -0
  277. package/types/lib/inventory/rubyHostProbe.d.ts +47 -0
  278. package/types/lib/inventory/rubyHostProbe.d.ts.map +1 -0
  279. package/types/lib/inventory/source.d.ts +38 -0
  280. package/types/lib/inventory/source.d.ts.map +1 -1
  281. package/types/lib/inventory/spdx.d.ts +15 -0
  282. package/types/lib/inventory/spdx.d.ts.map +1 -1
  283. package/types/lib/inventory/traceRunner.d.ts +4 -1
  284. package/types/lib/inventory/traceRunner.d.ts.map +1 -1
  285. package/types/lib/inventory/tracedCrypto.d.ts +22 -0
  286. package/types/lib/inventory/tracedCrypto.d.ts.map +1 -1
  287. package/types/lib/managers/binary.d.ts +10 -0
  288. package/types/lib/managers/binary.d.ts.map +1 -1
  289. package/types/lib/managers/docker.d.ts +24 -0
  290. package/types/lib/managers/docker.d.ts.map +1 -1
  291. package/types/lib/parsers/email.d.ts +19 -0
  292. package/types/lib/parsers/email.d.ts.map +1 -0
  293. package/types/lib/parsers/largeJson.d.ts +17 -3
  294. package/types/lib/parsers/largeJson.d.ts.map +1 -1
  295. package/types/lib/server/server.d.ts +8 -0
  296. package/types/lib/server/server.d.ts.map +1 -1
  297. package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
  298. package/types/lib/stages/postgen/introspection/reflect.d.ts.map +1 -1
  299. package/types/lib/stages/postgen/ruleEngine.d.ts +7 -4
  300. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  301. package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
  302. package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
  303. package/types/lib/stages/pregen/pregen.d.ts +26 -9
  304. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
  305. package/types/lib/validator/bomValidator.d.ts.map +1 -1
@@ -0,0 +1,140 @@
1
+ // Bounded Go buildinfo reader for executable file components: recovers the
2
+ // toolchain version a binary was built with, so a BOM can answer "which Go
3
+ // programs predate the CVE-2026-111943 distrust list". Only the header and
4
+ // the inline version string are read; pointer-based (pre-1.18) layouts are
5
+ // reported as such and never followed.
6
+ //
7
+ // Layout: go/src/debug/buildinfo/buildinfo.go at tag go1.27.2. The 14-byte
8
+ // magic `\xff Go buildinf:` is 16-byte aligned; the next two bytes are the
9
+ // pointer size and flags. When flags&2 is set the version string follows as a
10
+ // uvarint length plus bytes. The magic can appear anywhere in the file's
11
+ // initial segment, so the search scans aligned offsets up to a cap.
12
+
13
+ import { closeSync, fstatSync, openSync, readSync } from "node:fs";
14
+
15
+ const BUILD_INFO_MAGIC = Buffer.from([
16
+ 0xff, 0x20, 0x47, 0x6f, 0x20, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x69, 0x6e, 0x66,
17
+ 0x3a,
18
+ ]);
19
+ // The buildinfo section follows text and rodata, often late in the file
20
+ // (37 MB into a 40 MB gh binary), so the cap must cover large binaries.
21
+ const MAX_SEARCH_BYTES = 512 * 1024 * 1024;
22
+ const READ_CHUNK_BYTES = 64 * 1024;
23
+ const MAX_VERSION_BYTES = 128;
24
+ export const PRE_1_18_VERSION = "unknown-pre-1.18";
25
+
26
+ function readUvarint(buffer, offset) {
27
+ let value = 0;
28
+ let shift = 0;
29
+ for (let i = 0; i < 10 && offset + i < buffer.length; i++) {
30
+ const byte = buffer[offset + i];
31
+ value += (byte & 0x7f) * 2 ** shift;
32
+ if (!(byte & 0x80)) {
33
+ return { value, next: offset + i + 1 };
34
+ }
35
+ shift += 7;
36
+ }
37
+ return undefined;
38
+ }
39
+
40
+ function parseHeaderAt(buffer, offset, limit) {
41
+ if (offset + 32 > limit) {
42
+ return undefined;
43
+ }
44
+ for (let i = 0; i < BUILD_INFO_MAGIC.length; i++) {
45
+ if (buffer[offset + i] !== BUILD_INFO_MAGIC[i]) {
46
+ return undefined;
47
+ }
48
+ }
49
+ const pointerSize = buffer[offset + 14];
50
+ const flags = buffer[offset + 15];
51
+ if (pointerSize !== 4 && pointerSize !== 8) {
52
+ return undefined;
53
+ }
54
+ if (!(flags & 0x02)) {
55
+ // Version lives behind pointers (pre-1.18 layout): not followed.
56
+ return PRE_1_18_VERSION;
57
+ }
58
+ // The inline strings start 16 bytes past the magic header (magic 14 +
59
+ // pointerSize 1 + flags 1, then a reserved 16-byte slot), as a uvarint
60
+ // length followed by the bytes.
61
+ const varint = readUvarint(buffer, offset + 32);
62
+ if (
63
+ !varint ||
64
+ varint.value === 0 ||
65
+ varint.value > MAX_VERSION_BYTES ||
66
+ varint.next + varint.value > limit
67
+ ) {
68
+ return undefined;
69
+ }
70
+ const version = buffer.toString(
71
+ "latin1",
72
+ varint.next,
73
+ varint.next + varint.value,
74
+ );
75
+ if (!/^go[0-9]/.test(version)) {
76
+ return undefined;
77
+ }
78
+ return version;
79
+ }
80
+
81
+ /**
82
+ * Read the Go toolchain version from an executable's buildinfo header.
83
+ *
84
+ * @param {string} filePath absolute path to a possible Go binary
85
+ * @returns {string|undefined} `go1.x.y`, `unknown-pre-1.18` for old layouts,
86
+ * or undefined when the file carries no Go buildinfo
87
+ */
88
+ export function readGoBuildVersion(filePath) {
89
+ if (typeof filePath !== "string" || !filePath) {
90
+ return undefined;
91
+ }
92
+ let fd;
93
+ try {
94
+ fd = openSync(filePath, "r");
95
+ const size = fstatSync(fd).size;
96
+ if (size < 32) {
97
+ return undefined;
98
+ }
99
+ const searchLimit = Math.min(size, MAX_SEARCH_BYTES);
100
+ // Each chunk examines the aligned offsets that start inside its 64 KiB
101
+ // window, reading a fixed overlap past it so a header near the window
102
+ // end is parsed whole; the next chunk starts at the next window.
103
+ const OVERLAP_BYTES = 256;
104
+ const chunk = Buffer.alloc(READ_CHUNK_BYTES + OVERLAP_BYTES);
105
+ for (
106
+ let position = 0;
107
+ position < searchLimit;
108
+ position += READ_CHUNK_BYTES
109
+ ) {
110
+ const want = Math.min(READ_CHUNK_BYTES + OVERLAP_BYTES, size - position);
111
+ const read = readSync(fd, chunk, 0, want, position);
112
+ if (read < 32) {
113
+ return undefined;
114
+ }
115
+ // position is a multiple of 16, so chunk offsets stay on the file's
116
+ // 16-byte grid.
117
+ for (
118
+ let offset = 0;
119
+ offset < READ_CHUNK_BYTES && offset + 32 <= read;
120
+ offset += 16
121
+ ) {
122
+ const version = parseHeaderAt(chunk, offset, read);
123
+ if (version) {
124
+ return version;
125
+ }
126
+ }
127
+ }
128
+ return undefined;
129
+ } catch {
130
+ return undefined;
131
+ } finally {
132
+ if (fd !== undefined) {
133
+ try {
134
+ closeSync(fd);
135
+ } catch {
136
+ // already closed
137
+ }
138
+ }
139
+ }
140
+ }
@@ -17,6 +17,15 @@ const MATCH_FIELDS = [
17
17
  "executable",
18
18
  "description",
19
19
  ];
20
+ // Rows of these categories name an account, not a program: a user called
21
+ // `node` or `git` is no use of the binary of that name, and the GECOS comment
22
+ // in the description is free text about the account.
23
+ const ACCOUNT_CATEGORIES = new Set([
24
+ "authorized_keys_snapshot",
25
+ "logged_in_users_snapshot",
26
+ "users_snapshot",
27
+ ]);
28
+ const ACCOUNT_SKIPPED_FIELDS = new Set(["name", "description"]);
20
29
  const UNIX_PATH_PATTERN = /(?:^|[\s'"`=;|&(])((?:\.{0,2}\/|\/)[^\s'"`|;&()]+)/g;
21
30
  const STANDALONE_COMMAND_PATTERN =
22
31
  /(?:^|[\s;|&(])([a-z_][a-z0-9+._-]{1,})(?=$|[\s'"`|;&()])/gi;
@@ -250,7 +259,11 @@ export function createGtfoBinsProperties(name, linkedName) {
250
259
  */
251
260
  export function createGtfoBinsPropertiesFromRow(queryCategory, row) {
252
261
  const matches = new Map();
262
+ const isAccount = ACCOUNT_CATEGORIES.has(queryCategory);
253
263
  for (const field of MATCH_FIELDS) {
264
+ if (isAccount && ACCOUNT_SKIPPED_FIELDS.has(field)) {
265
+ continue;
266
+ }
254
267
  const fieldValue = row?.[field];
255
268
  if (!fieldValue) {
256
269
  continue;
@@ -1,4 +1,6 @@
1
- import { basename } from "node:path";
1
+ import { createHash } from "node:crypto";
2
+ import { basename, win32 } from "node:path";
3
+ import process from "node:process";
2
4
 
3
5
  import {
4
6
  isDryRun,
@@ -40,6 +42,18 @@ function getConfiguredHbomPathAllowlist() {
40
42
  );
41
43
  }
42
44
 
45
+ // A Windows plan can be inspected from any host (`getCommandPlan`), where
46
+ // node:path would not split a path on its backslashes.
47
+ function isWindowsStyleCommand(command) {
48
+ return command.includes("\\") || /^[A-Za-z]:/u.test(command);
49
+ }
50
+
51
+ function getHbomCommandName(command) {
52
+ return isWindowsStyleCommand(command)
53
+ ? win32.basename(command)
54
+ : basename(command);
55
+ }
56
+
43
57
  function isAllowedHbomCommand(command, allowlistValue = undefined) {
44
58
  const normalizedCommand = `${command ?? ""}`.trim();
45
59
  if (!normalizedCommand) {
@@ -51,7 +65,10 @@ function isAllowedHbomCommand(command, allowlistValue = undefined) {
51
65
  if (!allowlistEntries.length) {
52
66
  return true;
53
67
  }
54
- const commandName = basename(normalizedCommand);
68
+ // Exact and case-sensitive on purpose: cdx-hbom applies the same allowlist
69
+ // again when it spawns, so a looser preflight would pass here and then run
70
+ // nothing, which silently degrades the BOM.
71
+ const commandName = getHbomCommandName(normalizedCommand);
55
72
  return allowlistEntries.some(
56
73
  (entry) => entry === normalizedCommand || entry === commandName,
57
74
  );
@@ -61,9 +78,27 @@ function formatHbomCommandTarget(command, args = []) {
61
78
  return `${command}${args.length ? ` ${args.join(" ")}` : ""}`;
62
79
  }
63
80
 
81
+ // Windows plan entries carry a multi-kilobyte PowerShell script as their last
82
+ // argument. Like the cdx-hbom trace and evidence, the preflight names it by
83
+ // digest so a blocked run does not print every script.
84
+ function summarizeHbomPlanArgs(planEntry) {
85
+ const args = [...(planEntry.args || [])];
86
+ if (planEntry.parser !== "windows-envelope" || !args.length) {
87
+ return args;
88
+ }
89
+ const digest = createHash("sha256")
90
+ .update(String(args.at(-1)))
91
+ .digest("hex")
92
+ .slice(0, 12);
93
+ return ["-Command", planEntry.id, "script", `sha256:${digest}`];
94
+ }
95
+
64
96
  function buildHbomPlanActivities(planEntry, normalizedOptions) {
65
97
  const baseArgs = [...(planEntry.args || [])];
66
- const baseTarget = formatHbomCommandTarget(planEntry.command, baseArgs);
98
+ const baseTarget = formatHbomCommandTarget(
99
+ planEntry.command,
100
+ summarizeHbomPlanArgs(planEntry),
101
+ );
67
102
  const activities = [
68
103
  {
69
104
  args: baseArgs,
@@ -115,7 +150,7 @@ function collectDisallowedHbomCommands(
115
150
  }
116
151
  const existingEntry = disallowedCommands.get(requestedCommand) ?? {
117
152
  command: requestedCommand,
118
- commandName: basename(requestedCommand),
153
+ commandName: getHbomCommandName(requestedCommand),
119
154
  ids: new Set(),
120
155
  targets: new Set(),
121
156
  };
@@ -214,6 +249,28 @@ function createHbomAllowlistPreflightError(
214
249
  return new Error(messageLines.join("\n"));
215
250
  }
216
251
 
252
+ /**
253
+ * Whether cdx-hbom spawns no command for these collector options.
254
+ *
255
+ * Only the Linux collector reads `includeCommandEnrichment: false` as "run no
256
+ * commands", and even there the privileged dmidecode step still runs. The
257
+ * Darwin collector ignores the option, and the Windows collector always runs
258
+ * its `windows-cim-platform` batch, so those plans are checked in full.
259
+ *
260
+ * @param {object} normalizedOptions Collector options from normalizeHbomOptions
261
+ * @returns {boolean} `true` when the allowlist has nothing to check
262
+ */
263
+ function collectorSpawnsNoCommands(normalizedOptions) {
264
+ const targetPlatform = `${normalizedOptions.platform ?? process.platform}`
265
+ .trim()
266
+ .toLowerCase();
267
+ return (
268
+ normalizedOptions.includeCommandEnrichment === false &&
269
+ normalizedOptions.includePrivilegedEnrichment !== true &&
270
+ targetPlatform === "linux"
271
+ );
272
+ }
273
+
217
274
  async function enforceSecureModeHbomAllowlists(hbomModule, normalizedOptions) {
218
275
  if (isDryRun || normalizedOptions?.isDryRun || !isSecureMode) {
219
276
  return;
@@ -249,7 +306,7 @@ async function enforceSecureModeHbomAllowlists(hbomModule, normalizedOptions) {
249
306
  : [];
250
307
  } else if (
251
308
  hasCommandAllowlist &&
252
- normalizedOptions.includeCommandEnrichment !== false
309
+ !collectorSpawnsNoCommands(normalizedOptions)
253
310
  ) {
254
311
  traceActivities = hbomModule
255
312
  .getCommandPlan(normalizedOptions)
@@ -259,7 +316,7 @@ async function enforceSecureModeHbomAllowlists(hbomModule, normalizedOptions) {
259
316
  }
260
317
 
261
318
  const disallowedCommands =
262
- hasCommandAllowlist && normalizedOptions.includeCommandEnrichment !== false
319
+ hasCommandAllowlist && !collectorSpawnsNoCommands(normalizedOptions)
263
320
  ? collectDisallowedHbomCommands(traceActivities, commandAllowlistValue)
264
321
  : [];
265
322
  const disallowedPaths = hasPathAllowlist
@@ -398,8 +455,11 @@ export function normalizeHbomOptions(options = {}) {
398
455
  timeoutValue === undefined || timeoutValue === null || timeoutValue === ""
399
456
  ? undefined
400
457
  : Number.parseInt(`${timeoutValue}`, 10);
458
+ // yargs negates `--no-command-enrichment` into `commandEnrichment: false`
459
+ // and never sets `noCommandEnrichment`, so the CLIs rely on this spelling.
401
460
  const includeCommandEnrichment =
402
- options.includeCommandEnrichment ?? !options.noCommandEnrichment;
461
+ options.includeCommandEnrichment ??
462
+ (options.commandEnrichment !== false && !options.noCommandEnrichment);
403
463
  const allowPartial = options.allowPartial ?? !options.strict;
404
464
 
405
465
  return {
@@ -174,6 +174,22 @@ export function isHbomLikeBom(bomJson) {
174
174
  );
175
175
  }
176
176
 
177
+ /**
178
+ * Explain how the permission-denied enrichments of an HBOM can be recovered.
179
+ *
180
+ * Windows never uses sudo: the elevated-only batch needs an already-elevated
181
+ * session, and a network logon is denied every WMI query.
182
+ *
183
+ * @param {string|undefined} platform `cdx:hbom:platform` of the HBOM
184
+ * @returns {string} Guidance for the platform; the Linux wording for any other platform
185
+ */
186
+ export function getHbomPrivilegeGuidance(platform) {
187
+ if (`${platform ?? ""}`.toLowerCase() === "windows") {
188
+ return "Some Windows enrichments were denied. Run HBOM from a local session (a non-administrator over SSH or WinRM is denied every WMI query) and, for the TPM, BitLocker, storage-reliability and Secure Boot data, from an elevated (Run as administrator) prompt with --privileged. HBOM never prompts for elevation.";
189
+ }
190
+ return "Some Linux enrichments can likely succeed only with --privileged and a target environment that allows non-interactive sudo.";
191
+ }
192
+
177
193
  /**
178
194
  * Return a component's `cdx:hbom:hardwareClass` property value.
179
195
  *