@cyclonedx/cdxgen 12.3.3 → 12.4.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/README.md +64 -22
- package/bin/audit.js +21 -7
- package/bin/cdxgen.js +238 -116
- package/bin/convert.js +28 -13
- package/bin/hbom.js +490 -0
- package/bin/repl.js +580 -29
- package/bin/validate.js +34 -4
- package/bin/verify.js +40 -5
- package/data/README.md +298 -25
- package/data/component-tags.json +6 -0
- package/data/crypto-oid.json +16 -0
- package/data/predictive-audit-allowlist.json +11 -0
- package/data/queries-darwin.json +12 -1
- package/data/queries-win.json +7 -1
- package/data/queries.json +39 -2
- package/data/rules/ai-agent-governance.yaml +16 -0
- package/data/rules/asar-archives.yaml +150 -0
- package/data/rules/chrome-extensions.yaml +8 -0
- package/data/rules/ci-permissions.yaml +42 -18
- package/data/rules/container-risk.yaml +14 -7
- package/data/rules/dependency-sources.yaml +11 -0
- package/data/rules/hbom-compliance.yaml +325 -0
- package/data/rules/hbom-performance.yaml +307 -0
- package/data/rules/hbom-security.yaml +248 -0
- package/data/rules/host-topology.yaml +165 -0
- package/data/rules/mcp-servers.yaml +18 -3
- package/data/rules/obom-runtime.yaml +907 -22
- package/data/rules/package-integrity.yaml +14 -0
- package/data/rules/rootfs-hardening.yaml +179 -0
- package/data/rules/vscode-extensions.yaml +9 -0
- package/lib/audit/index.js +209 -8
- package/lib/audit/index.poku.js +332 -0
- package/lib/audit/reporters.js +222 -0
- package/lib/audit/targets.js +146 -1
- package/lib/audit/targets.poku.js +186 -0
- package/lib/cli/asar.poku.js +328 -0
- package/lib/cli/index.js +506 -88
- package/lib/cli/index.poku.js +1352 -212
- package/lib/evinser/evinser.js +14 -9
- package/lib/helpers/analyzer.js +1406 -29
- package/lib/helpers/analyzer.poku.js +342 -0
- package/lib/helpers/analyzerScope.js +712 -0
- package/lib/helpers/asarutils.js +1556 -0
- package/lib/helpers/asarutils.poku.js +443 -0
- package/lib/helpers/auditCategories.js +12 -0
- package/lib/helpers/auditCategories.poku.js +32 -0
- package/lib/helpers/cbomutils.js +271 -1
- package/lib/helpers/cbomutils.poku.js +248 -5
- package/lib/helpers/display.js +291 -1
- package/lib/helpers/display.poku.js +149 -0
- package/lib/helpers/evidenceUtils.js +58 -0
- package/lib/helpers/evidenceUtils.poku.js +54 -0
- package/lib/helpers/exportUtils.js +9 -0
- package/lib/helpers/gtfobins.js +142 -8
- package/lib/helpers/gtfobins.poku.js +24 -1
- package/lib/helpers/hbom.js +710 -0
- package/lib/helpers/hbom.poku.js +496 -0
- package/lib/helpers/hbomAnalysis.js +268 -0
- package/lib/helpers/hbomAnalysis.poku.js +249 -0
- package/lib/helpers/hbomLoader.js +35 -0
- package/lib/helpers/hostTopology.js +803 -0
- package/lib/helpers/hostTopology.poku.js +363 -0
- package/lib/helpers/inventoryStats.js +69 -0
- package/lib/helpers/inventoryStats.poku.js +86 -0
- package/lib/helpers/lolbas.js +19 -1
- package/lib/helpers/lolbas.poku.js +23 -0
- package/lib/helpers/osqueryTransform.js +47 -0
- package/lib/helpers/osqueryTransform.poku.js +47 -0
- package/lib/helpers/plugins.js +349 -0
- package/lib/helpers/plugins.poku.js +57 -0
- package/lib/helpers/protobom.js +156 -45
- package/lib/helpers/protobom.poku.js +140 -5
- package/lib/helpers/remote/dependency-track.js +36 -3
- package/lib/helpers/remote/dependency-track.poku.js +44 -0
- package/lib/helpers/source.js +24 -0
- package/lib/helpers/source.poku.js +32 -0
- package/lib/helpers/utils.js +1438 -93
- package/lib/helpers/utils.poku.js +846 -4
- package/lib/managers/binary.e2e.poku.js +367 -0
- package/lib/managers/binary.js +2293 -353
- package/lib/managers/binary.poku.js +1699 -1
- package/lib/managers/docker.js +201 -79
- package/lib/managers/docker.poku.js +337 -12
- package/lib/server/server.js +2 -27
- package/lib/stages/postgen/annotator.js +38 -0
- package/lib/stages/postgen/annotator.poku.js +107 -1
- package/lib/stages/postgen/auditBom.js +121 -18
- package/lib/stages/postgen/auditBom.poku.js +1366 -31
- package/lib/stages/postgen/hostTopologyAudit.poku.js +186 -0
- package/lib/stages/postgen/postgen.js +192 -1
- package/lib/stages/postgen/postgen.poku.js +321 -0
- package/lib/stages/postgen/ruleEngine.js +116 -0
- package/lib/stages/pregen/envAudit.js +14 -3
- package/package.json +23 -21
- package/types/bin/hbom.d.ts +3 -0
- package/types/bin/hbom.d.ts.map +1 -0
- package/types/bin/repl.d.ts.map +1 -1
- package/types/lib/audit/index.d.ts +44 -0
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/audit/reporters.d.ts +16 -0
- package/types/lib/audit/reporters.d.ts.map +1 -1
- package/types/lib/audit/targets.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts +16 -0
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +4 -0
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/helpers/analyzer.d.ts +33 -0
- package/types/lib/helpers/analyzer.d.ts.map +1 -1
- package/types/lib/helpers/analyzerScope.d.ts +11 -0
- package/types/lib/helpers/analyzerScope.d.ts.map +1 -0
- package/types/lib/helpers/asarutils.d.ts +34 -0
- package/types/lib/helpers/asarutils.d.ts.map +1 -0
- package/types/lib/helpers/auditCategories.d.ts +5 -0
- package/types/lib/helpers/auditCategories.d.ts.map +1 -1
- package/types/lib/helpers/cbomutils.d.ts +3 -2
- package/types/lib/helpers/cbomutils.d.ts.map +1 -1
- package/types/lib/helpers/display.d.ts.map +1 -1
- package/types/lib/helpers/evidenceUtils.d.ts +8 -0
- package/types/lib/helpers/evidenceUtils.d.ts.map +1 -0
- package/types/lib/helpers/exportUtils.d.ts.map +1 -1
- package/types/lib/helpers/gtfobins.d.ts +8 -0
- package/types/lib/helpers/gtfobins.d.ts.map +1 -1
- package/types/lib/helpers/hbom.d.ts +49 -0
- package/types/lib/helpers/hbom.d.ts.map +1 -0
- package/types/lib/helpers/hbomAnalysis.d.ts +62 -0
- package/types/lib/helpers/hbomAnalysis.d.ts.map +1 -0
- package/types/lib/helpers/hbomLoader.d.ts +7 -0
- package/types/lib/helpers/hbomLoader.d.ts.map +1 -0
- package/types/lib/helpers/hostTopology.d.ts +12 -0
- package/types/lib/helpers/hostTopology.d.ts.map +1 -0
- package/types/lib/helpers/inventoryStats.d.ts +11 -0
- package/types/lib/helpers/inventoryStats.d.ts.map +1 -0
- package/types/lib/helpers/lolbas.d.ts.map +1 -1
- package/types/lib/helpers/osqueryTransform.d.ts +3 -0
- package/types/lib/helpers/osqueryTransform.d.ts.map +1 -1
- package/types/lib/helpers/plugins.d.ts +58 -0
- package/types/lib/helpers/plugins.d.ts.map +1 -0
- package/types/lib/helpers/protobom.d.ts +3 -4
- package/types/lib/helpers/protobom.d.ts.map +1 -1
- package/types/lib/helpers/remote/dependency-track.d.ts +10 -3
- package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -1
- package/types/lib/helpers/source.d.ts.map +1 -1
- package/types/lib/helpers/utils.d.ts +45 -8
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts +5 -0
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/server/server.d.ts +2 -1
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
- package/types/lib/stages/postgen/auditBom.d.ts +26 -1
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts +2 -1
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
- package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
- package/data/spdx-model-v3.0.1.jsonld +0 -15999
package/bin/validate.js
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
retrieveCdxgenVersion,
|
|
29
29
|
safeExistsSync,
|
|
30
30
|
safeMkdirSync,
|
|
31
|
+
safeWriteSync,
|
|
31
32
|
} from "../lib/helpers/utils.js";
|
|
32
33
|
import { getBomWithOras } from "../lib/managers/oci.js";
|
|
33
34
|
import { shouldFail, validateBomAdvanced } from "../lib/validator/index.js";
|
|
@@ -39,7 +40,7 @@ const args = _yargs
|
|
|
39
40
|
.option("input", {
|
|
40
41
|
alias: "i",
|
|
41
42
|
default: "bom.json",
|
|
42
|
-
description: "Input SBOM JSON file or OCI reference.",
|
|
43
|
+
description: "Input SBOM JSON or protobuf file, or an OCI reference.",
|
|
43
44
|
})
|
|
44
45
|
.option("platform", {
|
|
45
46
|
description:
|
|
@@ -128,9 +129,18 @@ const args = _yargs
|
|
|
128
129
|
.help()
|
|
129
130
|
.wrap(Math.min(120, yargs().terminalWidth())).argv;
|
|
130
131
|
|
|
131
|
-
function loadBom(input, platform) {
|
|
132
|
+
async function loadBom(input, platform) {
|
|
132
133
|
if (safeExistsSync(input)) {
|
|
134
|
+
const normalizedInput = `${input}`.toLowerCase();
|
|
133
135
|
try {
|
|
136
|
+
if (
|
|
137
|
+
normalizedInput.endsWith(".cdx") ||
|
|
138
|
+
normalizedInput.endsWith(".cdx.bin") ||
|
|
139
|
+
normalizedInput.endsWith(".proto")
|
|
140
|
+
) {
|
|
141
|
+
const { readBinary } = await import("../lib/helpers/protobom.js");
|
|
142
|
+
return readBinary(input, true);
|
|
143
|
+
}
|
|
134
144
|
return JSON.parse(fs.readFileSync(input, "utf8"));
|
|
135
145
|
} catch (err) {
|
|
136
146
|
console.error(`Failed to parse ${input}: ${err.message}`);
|
|
@@ -176,16 +186,36 @@ function writeOrPrint(content, outputPath) {
|
|
|
176
186
|
if (parent && !safeExistsSync(parent)) {
|
|
177
187
|
safeMkdirSync(parent, { recursive: true });
|
|
178
188
|
}
|
|
179
|
-
|
|
189
|
+
safeWriteSync(outputPath, content);
|
|
180
190
|
}
|
|
181
191
|
|
|
182
|
-
|
|
192
|
+
function isLocalProtoBomInput(input) {
|
|
193
|
+
if (!safeExistsSync(input)) {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
const normalizedInput = `${input}`.toLowerCase();
|
|
197
|
+
return (
|
|
198
|
+
normalizedInput.endsWith(".cdx") ||
|
|
199
|
+
normalizedInput.endsWith(".cdx.bin") ||
|
|
200
|
+
normalizedInput.endsWith(".proto")
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const bomJson = await loadBom(args.input, args.platform);
|
|
183
205
|
const publicKeyStr = loadPublicKey(args.publicKey);
|
|
206
|
+
const inputIsLocalProtoBom = isLocalProtoBomInput(args.input);
|
|
184
207
|
if (!isCycloneDxBom(bomJson)) {
|
|
185
208
|
console.error(getNonCycloneDxErrorMessage(bomJson, "cdx-validate"));
|
|
186
209
|
process.exit(1);
|
|
187
210
|
}
|
|
188
211
|
|
|
212
|
+
if (inputIsLocalProtoBom && publicKeyStr) {
|
|
213
|
+
console.error(
|
|
214
|
+
"cdx-validate: protobuf BOM input does not currently preserve JSF signature blocks. Verify signatures against the source JSON BOM instead.",
|
|
215
|
+
);
|
|
216
|
+
process.exit(args.requireSignature ? 4 : 1);
|
|
217
|
+
}
|
|
218
|
+
|
|
189
219
|
const report = validateBomAdvanced(bomJson, {
|
|
190
220
|
schema: args.schema,
|
|
191
221
|
deep: args.deep,
|
package/bin/verify.js
CHANGED
|
@@ -27,7 +27,8 @@ const args = _yargs
|
|
|
27
27
|
.option("input", {
|
|
28
28
|
alias: "i",
|
|
29
29
|
default: "bom.json",
|
|
30
|
-
description:
|
|
30
|
+
description:
|
|
31
|
+
"Input CycloneDX JSON or protobuf BOM to verify. Default bom.json",
|
|
31
32
|
})
|
|
32
33
|
.option("platform", {
|
|
33
34
|
description: "The platform to validate. No default",
|
|
@@ -75,9 +76,23 @@ if (process.env?.CDXGEN_NODE_OPTIONS) {
|
|
|
75
76
|
process.env.NODE_OPTIONS = `${process.env.NODE_OPTIONS || ""} ${process.env.CDXGEN_NODE_OPTIONS}`;
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
function getBom(args) {
|
|
79
|
-
if (
|
|
80
|
-
|
|
79
|
+
async function getBom(args) {
|
|
80
|
+
if (safeExistsSync(args.input)) {
|
|
81
|
+
const normalizedInput = `${args.input}`.toLowerCase();
|
|
82
|
+
try {
|
|
83
|
+
if (
|
|
84
|
+
normalizedInput.endsWith(".cdx") ||
|
|
85
|
+
normalizedInput.endsWith(".cdx.bin") ||
|
|
86
|
+
normalizedInput.endsWith(".proto")
|
|
87
|
+
) {
|
|
88
|
+
const { readBinary } = await import("../lib/helpers/protobom.js");
|
|
89
|
+
return readBinary(args.input, true);
|
|
90
|
+
}
|
|
91
|
+
return JSON.parse(fs.readFileSync(args.input, "utf8"));
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.log(`Failed to parse '${args.input}': ${error.message}`);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
81
96
|
}
|
|
82
97
|
if (
|
|
83
98
|
args.input.includes(":") ||
|
|
@@ -89,7 +104,20 @@ function getBom(args) {
|
|
|
89
104
|
return undefined;
|
|
90
105
|
}
|
|
91
106
|
|
|
92
|
-
|
|
107
|
+
function isLocalProtoBomInput(input) {
|
|
108
|
+
if (!safeExistsSync(input)) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
const normalizedInput = `${input}`.toLowerCase();
|
|
112
|
+
return (
|
|
113
|
+
normalizedInput.endsWith(".cdx") ||
|
|
114
|
+
normalizedInput.endsWith(".cdx.bin") ||
|
|
115
|
+
normalizedInput.endsWith(".proto")
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const bomJson = await getBom(args);
|
|
120
|
+
const inputIsLocalProtoBom = isLocalProtoBomInput(args.input);
|
|
93
121
|
|
|
94
122
|
if (!bomJson) {
|
|
95
123
|
console.log(`${args.input} is invalid!`);
|
|
@@ -100,6 +128,13 @@ if (!isCycloneDxBom(bomJson)) {
|
|
|
100
128
|
process.exit(1);
|
|
101
129
|
}
|
|
102
130
|
|
|
131
|
+
if (inputIsLocalProtoBom) {
|
|
132
|
+
console.log(
|
|
133
|
+
"cdx-verify: protobuf BOM input does not currently preserve JSF signature blocks. Verify signatures against the source JSON BOM instead.",
|
|
134
|
+
);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
|
|
103
138
|
if (bomJson && !safeExistsSync(args.publicKey)) {
|
|
104
139
|
console.log("Public key for signature verification is missing!");
|
|
105
140
|
process.exit(1);
|
package/data/README.md
CHANGED
|
@@ -1,27 +1,300 @@
|
|
|
1
1
|
# Introduction
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
|
23
|
-
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
27
|
-
|
|
|
3
|
+
This directory contains static knowledge that cdxgen uses at runtime. Some files are passive reference data. Others directly shape behavior, especially query packs, rule files, schemas, aliases, and component-tag metadata.
|
|
4
|
+
|
|
5
|
+
## Purpose of this directory
|
|
6
|
+
|
|
7
|
+
Treat `data/` as product behavior, not as a convenient dump of reference files. If a file here is stale, incomplete, or incorrectly sourced, it can change runtime output, validation behavior, or audit findings.
|
|
8
|
+
|
|
9
|
+
## Contribution policy
|
|
10
|
+
|
|
11
|
+
Direct pull requests that only hand-edit curated data in `data/` are not accepted. Start with an issue or a broader change proposal that explains:
|
|
12
|
+
|
|
13
|
+
1. the upstream source of truth
|
|
14
|
+
2. whether the file is upstream, derived, or hand-curated
|
|
15
|
+
3. how it should be refreshed
|
|
16
|
+
4. what tests or validation prove the update is safe
|
|
17
|
+
|
|
18
|
+
Prefer adding or improving automation under `contrib/` over one-off manual edits.
|
|
19
|
+
|
|
20
|
+
## Directory contents
|
|
21
|
+
|
|
22
|
+
| Filename | Purpose | Source | Curation / refresh path |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| `bom-1.4.schema.json` | CycloneDX 1.4 JSON schema for legacy compatibility validation | CycloneDX specification schema | upstream-derived compatibility copy; active feature work should target 1.5–1.7 |
|
|
25
|
+
| `bom-1.5.schema.json` | CycloneDX 1.5 JSON schema for validation | CycloneDX specification schema | upstream-derived |
|
|
26
|
+
| `bom-1.6.schema.json` | CycloneDX 1.6 JSON schema for validation | CycloneDX specification schema | upstream-derived |
|
|
27
|
+
| `bom-1.7.schema.json` | CycloneDX 1.7 JSON schema for validation | CycloneDX specification schema | upstream-derived |
|
|
28
|
+
| `cbomosdb-queries.json` | osquery queries for identifying SSL packages in OS contexts | project-maintained query pack | hand-curated with tests; should evolve with query-pack review |
|
|
29
|
+
| `component-tags.json` | tags extracted from component descriptions for classification | project-maintained derived dataset | partially curated; automation opportunities remain |
|
|
30
|
+
| `container-knowledge-index.json` | reference knowledge for container analysis | project-maintained derived dataset | partially curated; automation opportunities remain |
|
|
31
|
+
| `cosdb-queries.json` | osquery queries useful for identifying OS packages for C | project-maintained query pack | hand-curated with tests |
|
|
32
|
+
| `crypto-oid.json` | OID mapping reference used for crypto-aware output | standards and project-maintained mapping inputs | curated compatibility dataset |
|
|
33
|
+
| `cryptography-defs.json` | cryptography inventory definitions | project-maintained definitions | curated; should be kept aligned with analyzer and CBOM logic |
|
|
34
|
+
| `frameworks-list.json` | string fragments used to classify framework components | project-maintained heuristics | hand-curated; good candidate for future automation |
|
|
35
|
+
| `gtfobins-index.json` | GTFOBins reference data used for Linux container and runtime executable enrichment | GTFOBins project data plus project normalization | derived and normalized for cdxgen |
|
|
36
|
+
| `known-licenses.json` | hard-coded license corrections | project-maintained compatibility fixes | hand-curated escape hatch; prefer upstream/source fixes when possible |
|
|
37
|
+
| `lic-mapping.json` | fallback license-name to identifier mapping | project-maintained mapping | hand-curated compatibility layer |
|
|
38
|
+
| `lolbas-index.json` | LOLBAS reference data used for Windows runtime findings | LOLBAS project data plus project normalization | derived and normalized for cdxgen |
|
|
39
|
+
| `predictive-audit-allowlist.json` | allowlist data for audit behavior | project-maintained heuristics | curated; should be reviewed alongside audit targeting logic |
|
|
40
|
+
| `pypi-pkg-aliases.json` | Python package-name alias data | project-maintained alias mapping | hand-curated compatibility layer |
|
|
41
|
+
| `python-stdlib.json` | Python standard-library entries that can be filtered out | Python stdlib references plus project normalization | derived list; automation opportunities remain |
|
|
42
|
+
| `queries.json` | Linux osquery query pack for OBOM and runtime inventory | project-maintained query pack | hand-curated with tests |
|
|
43
|
+
| `queries-win.json` | Windows osquery query pack | project-maintained query pack | hand-curated with tests |
|
|
44
|
+
| `queries-darwin.json` | macOS osquery query pack | project-maintained query pack | hand-curated with tests |
|
|
45
|
+
| `rules/` | built-in BOM audit rule packs in YAML | project-maintained rule packs | hand-authored rules validated by tests; users can also supply their own rule packs |
|
|
46
|
+
| `spdx-licenses.json` | SPDX license identifiers | SPDX License List data | upstream-derived |
|
|
47
|
+
| `spdx-export.schema.json` | SPDX 3.0.1 schema used during export validation | project-derived export schema generated from SPDX model artifacts | derived artifact; there is not a single upstream-published JSON schema that exactly matches this export use case |
|
|
48
|
+
| `spdx.schema.json` | SPDX schema for validation | SPDX JSON schema inputs used by the project | upstream-derived compatibility copy |
|
|
49
|
+
| `vendor-alias.json` | vendor or group-name alias fixes | project-maintained alias mapping | hand-curated compatibility layer; should eventually be reduced as heuristics improve |
|
|
50
|
+
| `wrapdb-releases.json` | Meson WrapDB release data | Meson WrapDB | derived artifact; refresh automation still needs to be formalized and maintained |
|
|
51
|
+
|
|
52
|
+
## How this directory fits into the architecture
|
|
53
|
+
|
|
54
|
+
### ASCII view
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
runtime code
|
|
58
|
+
|
|
|
59
|
+
+--> lib/cli/* -----------> alias files, framework lists, tag maps
|
|
60
|
+
|
|
|
61
|
+
+--> lib/stages/postgen/* -> rule packs, standards data, schemas
|
|
62
|
+
|
|
|
63
|
+
+--> lib/audit/* ---------> rules/, allowlists, scoring support data
|
|
64
|
+
|
|
|
65
|
+
+--> lib/validator/* -----> CycloneDX and SPDX schemas
|
|
66
|
+
|
|
|
67
|
+
+--> OBOM flows ----------> queries*.json, GTFOBins, LOLBAS, knowledge indexes
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Mermaid view
|
|
71
|
+
|
|
72
|
+
```mermaid
|
|
73
|
+
flowchart TD
|
|
74
|
+
A[data/] --> B[schemas]
|
|
75
|
+
A --> C[query packs]
|
|
76
|
+
A --> D[rule files]
|
|
77
|
+
A --> E[alias and mapping files]
|
|
78
|
+
A --> F[knowledge indexes]
|
|
79
|
+
B --> G[validator]
|
|
80
|
+
C --> H[OBOM and runtime inventory]
|
|
81
|
+
D --> I[audit engine]
|
|
82
|
+
E --> J[parsers and metadata helpers]
|
|
83
|
+
F --> K[container and runtime enrichment]
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Query-pack files
|
|
87
|
+
|
|
88
|
+
The three `queries*.json` files are platform-specific osquery packs. They describe what cdxgen should ask osquery for when generating OS and runtime inventory.
|
|
89
|
+
|
|
90
|
+
### Query-pack shape
|
|
91
|
+
|
|
92
|
+
| Field | Required | Purpose |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| `query` | yes | SQL executed against osquery |
|
|
95
|
+
| `description` | yes | human-readable explanation of the collection intent |
|
|
96
|
+
| `purlType` | yes | package URL type used for derived components |
|
|
97
|
+
| `componentType` | no | CycloneDX component type when `library` is not appropriate |
|
|
98
|
+
| `name` | no | component-name override for result sets that do not naturally expose one |
|
|
99
|
+
|
|
100
|
+
### Example mental model
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
queries.json entry
|
|
104
|
+
|
|
|
105
|
+
v
|
|
106
|
+
osquery runs SQL
|
|
107
|
+
|
|
|
108
|
+
v
|
|
109
|
+
rows come back
|
|
110
|
+
|
|
|
111
|
+
v
|
|
112
|
+
cdxgen maps rows into components using purlType and componentType
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Good query-pack hygiene
|
|
116
|
+
|
|
117
|
+
| Practice | Why it matters |
|
|
118
|
+
|---|---|
|
|
119
|
+
| keep descriptions specific | helps users understand collected categories |
|
|
120
|
+
| choose `componentType` carefully | affects how consumers interpret results |
|
|
121
|
+
| mirror cross-platform entries intentionally | reduces accidental platform drift |
|
|
122
|
+
| keep query scope safe and bounded | avoids expensive or unsafe collection |
|
|
123
|
+
|
|
124
|
+
## Rule files under `data/rules/`
|
|
125
|
+
|
|
126
|
+
Rule files are YAML packs consumed by the audit flow. Each file groups rules by a shared theme such as container risk, rootfs hardening, OBOM runtime posture, or AI agent governance.
|
|
127
|
+
|
|
128
|
+
### Rule evaluation flow
|
|
129
|
+
|
|
130
|
+
#### ASCII view
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
input BOM
|
|
134
|
+
|
|
|
135
|
+
v
|
|
136
|
+
load YAML rule pack
|
|
137
|
+
|
|
|
138
|
+
v
|
|
139
|
+
for each rule
|
|
140
|
+
|
|
|
141
|
+
+--> evaluate JSONata condition against BOM
|
|
142
|
+
+--> collect matching components
|
|
143
|
+
+--> build location object
|
|
144
|
+
+--> render message template
|
|
145
|
+
+--> attach mitigation, evidence, ATT&CK, and standards metadata
|
|
146
|
+
|
|
|
147
|
+
v
|
|
148
|
+
audit findings
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### Mermaid view
|
|
152
|
+
|
|
153
|
+
```mermaid
|
|
154
|
+
flowchart TD
|
|
155
|
+
A[BOM input] --> B[load rule YAML]
|
|
156
|
+
B --> C[evaluate condition]
|
|
157
|
+
C --> D{matched components?}
|
|
158
|
+
D -->|no| E[no finding]
|
|
159
|
+
D -->|yes| F[build location and message]
|
|
160
|
+
F --> G[attach mitigation and evidence]
|
|
161
|
+
G --> H[emit finding]
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Rule schema in practice
|
|
165
|
+
|
|
166
|
+
Each rule is a YAML list item. These fields matter most.
|
|
167
|
+
|
|
168
|
+
| Field | Required | Purpose |
|
|
169
|
+
|---|---|---|
|
|
170
|
+
| `id` | yes | unique stable identifier such as `CTR-001` |
|
|
171
|
+
| `name` | yes | short title used in findings |
|
|
172
|
+
| `description` | yes | why the rule exists and what it detects |
|
|
173
|
+
| `severity` | yes | risk level such as `critical`, `high`, `medium`, `low`, `info` |
|
|
174
|
+
| `category` | yes | thematic category that usually aligns with the file grouping |
|
|
175
|
+
| `dry-run-support` | yes | whether the rule can work on dry-run style BOMs |
|
|
176
|
+
| `condition` | yes | JSONata expression that selects matching components |
|
|
177
|
+
| `location` | yes | JSONata expression that builds a location object for the match |
|
|
178
|
+
| `message` | yes | rendered finding text, including placeholders |
|
|
179
|
+
| `mitigation` | yes | remediation guidance shown with the finding |
|
|
180
|
+
| `evidence` | no | extra structured data carried with the finding |
|
|
181
|
+
| `attack` | no | MITRE ATT&CK mapping data |
|
|
182
|
+
| `standards` | no | mapping of standard names to reference identifiers; surfaced in audit annotations as `cdx:audit:standards:*` metadata |
|
|
183
|
+
|
|
184
|
+
## Writing `condition` expressions
|
|
185
|
+
|
|
186
|
+
Conditions are written in JSONata and evaluated against the BOM document. In practice, most rules filter the `components` array.
|
|
187
|
+
|
|
188
|
+
```yaml
|
|
189
|
+
condition: |
|
|
190
|
+
components[
|
|
191
|
+
$prop($, 'cdx:some:property') = 'expected-value'
|
|
192
|
+
and type = 'library'
|
|
193
|
+
]
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Helper functions commonly used in rules
|
|
197
|
+
|
|
198
|
+
| Function | Purpose |
|
|
199
|
+
|---|---|
|
|
200
|
+
| `$prop(component, name)` | fetches a CycloneDX property by name |
|
|
201
|
+
| `$nullSafeProp(component, name)` | null-safe property fetch for comparisons |
|
|
202
|
+
| `$listContains(list, value)` | checks list-like property text for a specific entry |
|
|
203
|
+
| `$firstNonEmpty(a, b, ...)` | returns the first non-empty value |
|
|
204
|
+
|
|
205
|
+
### Thinking about rule conditions
|
|
206
|
+
|
|
207
|
+
A good condition is usually:
|
|
208
|
+
|
|
209
|
+
1. specific enough to avoid noise
|
|
210
|
+
2. readable enough for reviewers to reason about
|
|
211
|
+
3. based on stable properties that cdxgen already emits consistently
|
|
212
|
+
|
|
213
|
+
## Message rendering
|
|
214
|
+
|
|
215
|
+
The `message` field supports template placeholders using double braces.
|
|
216
|
+
|
|
217
|
+
```yaml
|
|
218
|
+
message: "Package '{{ name }}' at version '{{ version }}' is affected"
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Those expressions are evaluated in the context of the matched component. Keep messages clear and reviewer-friendly. The message should explain the risk without requiring the reader to decode the raw JSONata condition.
|
|
222
|
+
|
|
223
|
+
## Authoring rules with the REPL
|
|
224
|
+
|
|
225
|
+
Use `cdxi` when you want a tight feedback loop while authoring or debugging a rule. A practical flow is:
|
|
226
|
+
|
|
227
|
+
```text
|
|
228
|
+
cdxi bom.json
|
|
229
|
+
.query components[type = 'library']
|
|
230
|
+
.query components[$prop($, 'cdx:github:action:isShaPinned') = 'false']
|
|
231
|
+
.auditfindings
|
|
232
|
+
.validate
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Why this helps:
|
|
236
|
+
|
|
237
|
+
| REPL command | Use while authoring rules |
|
|
238
|
+
|---|---|
|
|
239
|
+
| `.query <jsonata>` | test the JSONata shape before copying it into a YAML rule |
|
|
240
|
+
| `.inspect <name-or-purl>` | inspect a concrete component when a condition is too broad or too narrow |
|
|
241
|
+
| `.auditfindings` | review existing annotations produced by `--bom-audit` or `cdx-audit` |
|
|
242
|
+
| `.validate` | quickly validate the loaded BOM before concluding the rule is wrong |
|
|
243
|
+
|
|
244
|
+
## Using custom rule packs
|
|
245
|
+
|
|
246
|
+
Users can maintain their own rule packs outside this repository and supply the directory at runtime.
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
# Apply custom rules during BOM generation
|
|
250
|
+
cdxgen --bom-audit --bom-audit-rules-dir ./my-rules -o bom.json
|
|
251
|
+
|
|
252
|
+
# Apply custom rules with the standalone audit command
|
|
253
|
+
cdx-audit --bom bom.json --direct-bom-audit --rules-dir ./my-rules
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
This is the preferred path for organization-specific policy rather than submitting narrowly scoped custom rules into `data/rules/`.
|
|
257
|
+
|
|
258
|
+
## Adding a new rule safely
|
|
259
|
+
|
|
260
|
+
Use this sequence.
|
|
261
|
+
|
|
262
|
+
1. choose the correct category file under `data/rules/`
|
|
263
|
+
2. draft the condition against a real BOM sample
|
|
264
|
+
3. keep the location object small and actionable
|
|
265
|
+
4. add mitigation text that tells the user what to do next
|
|
266
|
+
5. add or update tests in `lib/stages/postgen/auditBom.poku.js`
|
|
267
|
+
|
|
268
|
+
## Choosing between a rule, a query-pack entry, and a helper-data file
|
|
269
|
+
|
|
270
|
+
| If you need to add... | It probably belongs in... |
|
|
271
|
+
|---|---|
|
|
272
|
+
| a new risk detection idea over existing BOM fields | `data/rules/*.yaml` |
|
|
273
|
+
| a new host or runtime collection source | `queries*.json` |
|
|
274
|
+
| a new alias, mapping, or classifier list | another JSON file in `data/` |
|
|
275
|
+
| a new schema or validation artifact | `data/*schema*.json` |
|
|
276
|
+
|
|
277
|
+
## Automation and maintenance gaps
|
|
278
|
+
|
|
279
|
+
Some files in `data/` are still compatibility layers, hand-curated heuristics, or locally derived artifacts. The goal should be to reduce those hacks over time, not normalize them.
|
|
280
|
+
|
|
281
|
+
Current expectations:
|
|
282
|
+
|
|
283
|
+
1. open an issue before proposing a new refresh process or replacing a derived artifact
|
|
284
|
+
2. document the upstream source and whether the file is hand-curated, upstream, or locally derived
|
|
285
|
+
3. prefer a repeatable refresh script under `contrib/` where practical
|
|
286
|
+
4. keep tests close to any rule or query-pack change
|
|
287
|
+
|
|
288
|
+
`wrapdb-releases.json` remains a derived artifact, but its refresh path still needs to be formalized and maintained like the rest of the curated datasets. Those gaps should be tracked as issue-first follow-up work rather than solved with silent one-off edits.
|
|
289
|
+
|
|
290
|
+
## Maintenance advice
|
|
291
|
+
|
|
292
|
+
This directory changes slowly, but small mistakes here can affect a lot of runtime behavior. Treat edits as code, not content.
|
|
293
|
+
|
|
294
|
+
| Habit | Why it helps |
|
|
295
|
+
|---|---|
|
|
296
|
+
| keep examples close to real emitted fields | avoids stale rules |
|
|
297
|
+
| review platform symmetry for query packs | avoids one-OS regressions |
|
|
298
|
+
| test new rules with realistic BOM fixtures | catches false positives early |
|
|
299
|
+
| document new files here | keeps contributors oriented |
|
|
300
|
+
| replace hacks with sourced or scripted refresh paths when possible | keeps long-term maintenance manageable |
|
package/data/component-tags.json
CHANGED
|
@@ -158,6 +158,7 @@
|
|
|
158
158
|
"processor",
|
|
159
159
|
"services_snapshot",
|
|
160
160
|
"apt_sources",
|
|
161
|
+
"apt_ppa_sources",
|
|
161
162
|
"behavioral_reverse_shell",
|
|
162
163
|
"certificates",
|
|
163
164
|
"chrome_extensions",
|
|
@@ -169,6 +170,7 @@
|
|
|
169
170
|
"docker_volumes",
|
|
170
171
|
"etc_hosts",
|
|
171
172
|
"firefox_addons",
|
|
173
|
+
"gatekeeper",
|
|
172
174
|
"vscode_extensions",
|
|
173
175
|
"homebrew_packages",
|
|
174
176
|
"installed_applications",
|
|
@@ -183,13 +185,16 @@
|
|
|
183
185
|
"pipes_snapshot",
|
|
184
186
|
"portage_packages",
|
|
185
187
|
"process_events",
|
|
188
|
+
"secureboot_certificates",
|
|
186
189
|
"processes",
|
|
187
190
|
"python_packages",
|
|
191
|
+
"npm_packages",
|
|
188
192
|
"rpm_packages",
|
|
189
193
|
"scheduled_tasks",
|
|
190
194
|
"services_snapshot",
|
|
191
195
|
"startup_items",
|
|
192
196
|
"system_info_snapshot",
|
|
197
|
+
"trusted_gpg_keys",
|
|
193
198
|
"windows_drivers",
|
|
194
199
|
"windows_patches",
|
|
195
200
|
"windows_programs",
|
|
@@ -207,6 +212,7 @@
|
|
|
207
212
|
"npm_packages",
|
|
208
213
|
"opera_extensions",
|
|
209
214
|
"pipes_snapshot",
|
|
215
|
+
"process_open_handles_snapshot",
|
|
210
216
|
"process_open_sockets",
|
|
211
217
|
"safari_extensions",
|
|
212
218
|
"scheduled_tasks",
|
package/data/crypto-oid.json
CHANGED
|
@@ -1023,6 +1023,22 @@
|
|
|
1023
1023
|
"oid": "1.3.101.113",
|
|
1024
1024
|
"description": "EdDSA 448 signature algorithm"
|
|
1025
1025
|
},
|
|
1026
|
+
"Ed25519": {
|
|
1027
|
+
"oid": "1.3.101.112",
|
|
1028
|
+
"description": "EdDSA 25519 signature algorithm"
|
|
1029
|
+
},
|
|
1030
|
+
"ed25519": {
|
|
1031
|
+
"oid": "1.3.101.112",
|
|
1032
|
+
"description": "EdDSA 25519 signature algorithm"
|
|
1033
|
+
},
|
|
1034
|
+
"Ed448": {
|
|
1035
|
+
"oid": "1.3.101.113",
|
|
1036
|
+
"description": "EdDSA 448 signature algorithm"
|
|
1037
|
+
},
|
|
1038
|
+
"ed448": {
|
|
1039
|
+
"oid": "1.3.101.113",
|
|
1040
|
+
"description": "EdDSA 448 signature algorithm"
|
|
1041
|
+
},
|
|
1026
1042
|
"curveEd25519ph": {
|
|
1027
1043
|
"oid": "1.3.101.114",
|
|
1028
1044
|
"description": "EdDSA 25519 pre-hash signature algorithm"
|
package/data/queries-darwin.json
CHANGED
|
@@ -35,6 +35,12 @@
|
|
|
35
35
|
"purlType": "swid",
|
|
36
36
|
"componentType": "application"
|
|
37
37
|
},
|
|
38
|
+
"gatekeeper": {
|
|
39
|
+
"query": "SELECT 'gatekeeper' as name, COALESCE(NULLIF(version, ''), opaque_version) as version, opaque_version as description, assessments_enabled, dev_id_enabled FROM gatekeeper;",
|
|
40
|
+
"description": "macOS Gatekeeper policy status, including assessment enforcement and identified-developer allowance.",
|
|
41
|
+
"purlType": "swid",
|
|
42
|
+
"componentType": "data"
|
|
43
|
+
},
|
|
38
44
|
"system_extensions": {
|
|
39
45
|
"query": "select * from system_extensions;",
|
|
40
46
|
"description": "macOS (>= 10.15) system extension table.",
|
|
@@ -71,6 +77,11 @@
|
|
|
71
77
|
"purlType": "swid",
|
|
72
78
|
"componentType": "application"
|
|
73
79
|
},
|
|
80
|
+
"npm_packages": {
|
|
81
|
+
"query": "SELECT * FROM npm_packages;",
|
|
82
|
+
"description": "Node packages installed on the system, including recursively discovered modern package manager layouts.",
|
|
83
|
+
"purlType": "npm"
|
|
84
|
+
},
|
|
74
85
|
"launchd_services": {
|
|
75
86
|
"query": "SELECT name, label, path, program, run_at_load, keep_alive, disabled, username, groupname, stdout_path, stderr_path, start_interval, program_arguments, watch_paths, queue_directories, start_on_mount, working_directory, process_type FROM launchd;",
|
|
76
87
|
"description": "LaunchAgents and LaunchDaemons configuration used for macOS persistence.",
|
|
@@ -108,7 +119,7 @@
|
|
|
108
119
|
"componentType": "data"
|
|
109
120
|
},
|
|
110
121
|
"package_bom": {
|
|
111
|
-
"query": "SELECT * FROM package_bom;",
|
|
122
|
+
"query": "SELECT * FROM package_bom WHERE path IN (SELECT REPLACE(package_receipts.path, '.plist', '.bom') FROM package_receipts JOIN file ON file.path = REPLACE(package_receipts.path, '.plist', '.bom') WHERE package_receipts.path LIKE '%.plist' AND file.size <= 52428800);",
|
|
112
123
|
"description": "macOS package bill of materials (BOM) file list.",
|
|
113
124
|
"purlType": "swid",
|
|
114
125
|
"componentType": "application"
|
package/data/queries-win.json
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"purlType": "swid"
|
|
37
37
|
},
|
|
38
38
|
"ie_extensions": {
|
|
39
|
-
"query": "select
|
|
39
|
+
"query": "select * from ie_extensions;",
|
|
40
40
|
"description": "Retrieves the list of extensions for IE in the target system.",
|
|
41
41
|
"purlType": "swid"
|
|
42
42
|
},
|
|
@@ -112,6 +112,12 @@
|
|
|
112
112
|
"purlType": "swid",
|
|
113
113
|
"componentType": "data"
|
|
114
114
|
},
|
|
115
|
+
"process_open_handles_snapshot": {
|
|
116
|
+
"query": "SELECT processes.name, process_open_handles.type as version, process_open_handles.name as description, processes.path, processes.cmdline, processes.pid, process_open_handles.value, process_open_handles.type, process_open_handles.name as handle_name, process_open_handles.access, process_open_handles.attributes, process_open_handles.count, process_open_handles.raw_pointer_count, process_open_handles.error_stage, process_open_handles.error_code FROM processes JOIN process_open_handles USING (pid) WHERE process_open_handles.name != '' AND processes.name IN ('powershell.exe', 'pwsh.exe', 'cmd.exe', 'wscript.exe', 'cscript.exe', 'mshta.exe', 'rundll32.exe', 'regsvr32.exe', 'wmic.exe', 'certutil.exe', 'bitsadmin.exe') AND ((process_open_handles.type = 'File' AND (lower(process_open_handles.name) LIKE '%\\appdata\\local\\temp\\%' OR lower(process_open_handles.name) LIKE '%\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\startup\\%' OR lower(process_open_handles.name) LIKE '%\\programdata\\microsoft\\windows\\start menu\\programs\\startup\\%' OR lower(process_open_handles.name) LIKE '%\\windows\\tasks\\%' OR lower(process_open_handles.name) LIKE '%\\system32\\tasks\\%' OR lower(process_open_handles.name) LIKE '%\\wbem\\repository\\%')) OR (process_open_handles.type = 'Key' AND (lower(process_open_handles.name) LIKE '%\\software\\microsoft\\windows\\currentversion\\run%' OR lower(process_open_handles.name) LIKE '%\\software\\microsoft\\windows\\currentversion\\runonce%' OR lower(process_open_handles.name) LIKE '%\\software\\microsoft\\windows nt\\currentversion\\winlogon%' OR lower(process_open_handles.name) LIKE '%\\system\\currentcontrolset\\services\\%' OR lower(process_open_handles.name) LIKE '%\\software\\microsoft\\windows nt\\currentversion\\schedule\\taskcache\\%' OR lower(process_open_handles.name) LIKE '%\\software\\microsoft\\wbem\\cimom%')));",
|
|
117
|
+
"description": "Open handles owned by high-signal scripting and proxy-execution processes, filtered to persistence-oriented file and registry locations on Windows endpoints.",
|
|
118
|
+
"purlType": "swid",
|
|
119
|
+
"componentType": "data"
|
|
120
|
+
},
|
|
115
121
|
"services_snapshot": {
|
|
116
122
|
"query": "SELECT * FROM services;",
|
|
117
123
|
"description": "Services snapshot query.",
|