@cyclonedx/cdxgen 12.1.4 → 12.2.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 +47 -39
- package/bin/cdxgen.js +181 -90
- package/bin/evinse.js +4 -4
- package/bin/repl.js +3 -3
- package/bin/sign.js +102 -0
- package/bin/validate.js +233 -0
- package/bin/verify.js +69 -28
- package/data/queries.json +1 -1
- package/data/rules/ci-permissions.yaml +186 -0
- package/data/rules/dependency-sources.yaml +123 -0
- package/data/rules/package-integrity.yaml +135 -0
- package/data/rules/vscode-extensions.yaml +228 -0
- package/lib/cli/index.js +484 -440
- package/lib/evinser/db.js +137 -0
- package/lib/{helpers → evinser}/db.poku.js +2 -6
- package/lib/evinser/evinser.js +5 -18
- package/lib/evinser/swiftsem.js +1 -1
- package/lib/helpers/bomSigner.js +312 -0
- package/lib/helpers/bomSigner.poku.js +156 -0
- package/lib/helpers/caxa.js +1 -1
- package/lib/helpers/ciParsers/azurePipelines.js +295 -0
- package/lib/helpers/ciParsers/azurePipelines.poku.js +253 -0
- package/lib/helpers/ciParsers/circleCi.js +286 -0
- package/lib/helpers/ciParsers/circleCi.poku.js +230 -0
- package/lib/helpers/ciParsers/common.js +24 -0
- package/lib/helpers/ciParsers/githubActions.js +636 -0
- package/lib/helpers/ciParsers/githubActions.poku.js +802 -0
- package/lib/helpers/ciParsers/gitlabCi.js +213 -0
- package/lib/helpers/ciParsers/gitlabCi.poku.js +247 -0
- package/lib/helpers/ciParsers/jenkins.js +181 -0
- package/lib/helpers/ciParsers/jenkins.poku.js +197 -0
- package/lib/helpers/depsUtils.js +203 -0
- package/lib/helpers/depsUtils.poku.js +150 -0
- package/lib/helpers/display.js +429 -14
- package/lib/helpers/envcontext.js +23 -8
- package/lib/helpers/formulationParsers.js +351 -0
- package/lib/helpers/logger.js +14 -0
- package/lib/helpers/protobom.js +9 -9
- package/lib/helpers/pythonutils.js +305 -0
- package/lib/helpers/pythonutils.poku.js +469 -0
- package/lib/helpers/utils.js +970 -528
- package/lib/helpers/utils.poku.js +139 -256
- package/lib/helpers/versutils.js +202 -0
- package/lib/helpers/versutils.poku.js +315 -0
- package/lib/helpers/vsixutils.js +1061 -0
- package/lib/helpers/vsixutils.poku.js +2247 -0
- package/lib/managers/binary.js +19 -19
- package/lib/managers/docker.js +108 -1
- package/lib/managers/oci.js +10 -0
- package/lib/managers/piptree.js +4 -10
- package/lib/parsers/npmrc.js +92 -0
- package/lib/parsers/npmrc.poku.js +528 -0
- package/lib/server/openapi.yaml +1 -10
- package/lib/server/server.js +58 -16
- package/lib/server/server.poku.js +123 -144
- package/lib/stages/postgen/annotator.js +1 -1
- package/lib/stages/postgen/auditBom.js +197 -0
- package/lib/stages/postgen/auditBom.poku.js +378 -0
- package/lib/stages/postgen/postgen.js +54 -1
- package/lib/stages/postgen/postgen.poku.js +90 -1
- package/lib/stages/postgen/ruleEngine.js +369 -0
- package/lib/stages/pregen/envAudit.js +299 -0
- package/lib/stages/pregen/envAudit.poku.js +572 -0
- package/lib/stages/pregen/pregen.js +12 -8
- package/lib/third-party/arborist/lib/deepest-nesting-target.js +1 -1
- package/lib/third-party/arborist/lib/node.js +3 -3
- package/lib/third-party/arborist/lib/shrinkwrap.js +1 -1
- package/lib/third-party/arborist/lib/tree-check.js +1 -1
- package/lib/{helpers/validator.js → validator/bomValidator.js} +107 -47
- package/lib/validator/complianceEngine.js +241 -0
- package/lib/validator/complianceEngine.poku.js +168 -0
- package/lib/validator/complianceRules.js +1610 -0
- package/lib/validator/complianceRules.poku.js +328 -0
- package/lib/validator/index.js +222 -0
- package/lib/validator/index.poku.js +144 -0
- package/lib/validator/reporters/annotations.js +121 -0
- package/lib/validator/reporters/console.js +149 -0
- package/lib/validator/reporters/index.js +41 -0
- package/lib/validator/reporters/json.js +37 -0
- package/lib/validator/reporters/sarif.js +184 -0
- package/lib/validator/reporters.poku.js +150 -0
- package/package.json +8 -8
- package/types/bin/sign.d.ts +3 -0
- package/types/bin/sign.d.ts.map +1 -0
- package/types/bin/validate.d.ts +3 -0
- package/types/bin/validate.d.ts.map +1 -0
- package/types/helpers/utils.d.ts +0 -1
- package/types/lib/cli/index.d.ts +49 -52
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/evinser/db.d.ts +34 -0
- package/types/lib/evinser/db.d.ts.map +1 -0
- package/types/lib/evinser/evinser.d.ts +63 -16
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/helpers/bomSigner.d.ts +27 -0
- package/types/lib/helpers/bomSigner.d.ts.map +1 -0
- package/types/lib/helpers/ciParsers/azurePipelines.d.ts +17 -0
- package/types/lib/helpers/ciParsers/azurePipelines.d.ts.map +1 -0
- package/types/lib/helpers/ciParsers/circleCi.d.ts +17 -0
- package/types/lib/helpers/ciParsers/circleCi.d.ts.map +1 -0
- package/types/lib/helpers/ciParsers/common.d.ts +11 -0
- package/types/lib/helpers/ciParsers/common.d.ts.map +1 -0
- package/types/lib/helpers/ciParsers/githubActions.d.ts +34 -0
- package/types/lib/helpers/ciParsers/githubActions.d.ts.map +1 -0
- package/types/lib/helpers/ciParsers/gitlabCi.d.ts +17 -0
- package/types/lib/helpers/ciParsers/gitlabCi.d.ts.map +1 -0
- package/types/lib/helpers/ciParsers/jenkins.d.ts +17 -0
- package/types/lib/helpers/ciParsers/jenkins.d.ts.map +1 -0
- package/types/lib/helpers/depsUtils.d.ts +21 -0
- package/types/lib/helpers/depsUtils.d.ts.map +1 -0
- package/types/lib/helpers/display.d.ts +111 -11
- package/types/lib/helpers/display.d.ts.map +1 -1
- package/types/lib/helpers/envcontext.d.ts +19 -7
- package/types/lib/helpers/envcontext.d.ts.map +1 -1
- package/types/lib/helpers/formulationParsers.d.ts +50 -0
- package/types/lib/helpers/formulationParsers.d.ts.map +1 -0
- package/types/lib/helpers/logger.d.ts +15 -1
- package/types/lib/helpers/logger.d.ts.map +1 -1
- package/types/lib/helpers/protobom.d.ts +2 -2
- package/types/lib/helpers/pythonutils.d.ts +18 -0
- package/types/lib/helpers/pythonutils.d.ts.map +1 -0
- package/types/lib/helpers/utils.d.ts +532 -128
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/helpers/versutils.d.ts +8 -0
- package/types/lib/helpers/versutils.d.ts.map +1 -0
- package/types/lib/helpers/vsixutils.d.ts +130 -0
- package/types/lib/helpers/vsixutils.d.ts.map +1 -0
- package/types/lib/managers/docker.d.ts +12 -31
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/managers/oci.d.ts +11 -1
- package/types/lib/managers/oci.d.ts.map +1 -1
- package/types/lib/managers/piptree.d.ts.map +1 -1
- package/types/lib/parsers/npmrc.d.ts +26 -0
- package/types/lib/parsers/npmrc.d.ts.map +1 -0
- package/types/lib/server/server.d.ts +21 -2
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/auditBom.d.ts +20 -0
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -0
- package/types/lib/stages/postgen/postgen.d.ts +8 -1
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts +18 -0
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -0
- package/types/lib/stages/pregen/envAudit.d.ts +8 -0
- package/types/lib/stages/pregen/envAudit.d.ts.map +1 -0
- package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
- package/types/lib/{helpers/validator.d.ts → validator/bomValidator.d.ts} +1 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -0
- package/types/lib/validator/complianceEngine.d.ts +66 -0
- package/types/lib/validator/complianceEngine.d.ts.map +1 -0
- package/types/lib/validator/complianceRules.d.ts +70 -0
- package/types/lib/validator/complianceRules.d.ts.map +1 -0
- package/types/lib/validator/index.d.ts +70 -0
- package/types/lib/validator/index.d.ts.map +1 -0
- package/types/lib/validator/reporters/annotations.d.ts +31 -0
- package/types/lib/validator/reporters/annotations.d.ts.map +1 -0
- package/types/lib/validator/reporters/console.d.ts +30 -0
- package/types/lib/validator/reporters/console.d.ts.map +1 -0
- package/types/lib/validator/reporters/index.d.ts +21 -0
- package/types/lib/validator/reporters/index.d.ts.map +1 -0
- package/types/lib/validator/reporters/json.d.ts +11 -0
- package/types/lib/validator/reporters/json.d.ts.map +1 -0
- package/types/lib/validator/reporters/sarif.d.ts +16 -0
- package/types/lib/validator/reporters/sarif.d.ts.map +1 -0
- package/lib/helpers/db.js +0 -162
- package/types/helpers/db.d.ts +0 -35
- package/types/helpers/db.d.ts.map +0 -1
- package/types/lib/helpers/db.d.ts +0 -35
- package/types/lib/helpers/db.d.ts.map +0 -1
- package/types/lib/helpers/validator.d.ts.map +0 -1
- package/types/managers/binary.d.ts +0 -37
- package/types/managers/binary.d.ts.map +0 -1
- package/types/managers/docker.d.ts +0 -56
- package/types/managers/docker.d.ts.map +0 -1
- package/types/managers/oci.d.ts +0 -2
- package/types/managers/oci.d.ts.map +0 -1
- package/types/managers/piptree.d.ts +0 -2
- package/types/managers/piptree.d.ts.map +0 -1
- package/types/server/server.d.ts +0 -34
- package/types/server/server.d.ts.map +0 -1
- package/types/stages/postgen/annotator.d.ts +0 -27
- package/types/stages/postgen/annotator.d.ts.map +0 -1
- package/types/stages/postgen/postgen.d.ts +0 -51
- package/types/stages/postgen/postgen.d.ts.map +0 -1
- package/types/stages/pregen/pregen.d.ts +0 -59
- package/types/stages/pregen/pregen.d.ts.map +0 -1
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
|
|
3
|
+
const PERMISSION_FLAGS = [
|
|
4
|
+
"--permission",
|
|
5
|
+
"--allow-fs-read",
|
|
6
|
+
"--allow-fs-write",
|
|
7
|
+
"--allow-child-process",
|
|
8
|
+
"--allow-addons",
|
|
9
|
+
"--allow-worker",
|
|
10
|
+
"--allow-net",
|
|
11
|
+
"--allow-env",
|
|
12
|
+
"--allow-wasi",
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
// Flags that allow arbitrary code execution or debugger attachment when set via NODE_OPTIONS.
|
|
16
|
+
const CODE_EXECUTION_PATTERNS = [
|
|
17
|
+
/--require\b/i,
|
|
18
|
+
/--eval\b/i,
|
|
19
|
+
/--print\b/i,
|
|
20
|
+
/--import\b/i,
|
|
21
|
+
/--loader\b/i,
|
|
22
|
+
/--inspect(-brk)?\b/i,
|
|
23
|
+
/--env-file\b/i,
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
// JVM flags that allow class/agent injection.
|
|
27
|
+
const JVM_CODE_EXECUTION_PATTERNS = [
|
|
28
|
+
/-javaagent\b/i,
|
|
29
|
+
/-agentlib\b/i,
|
|
30
|
+
/-agentpath\b/i,
|
|
31
|
+
/-Djdk\.module\.illegalAccess/i,
|
|
32
|
+
/--add-opens\b/i,
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
// Environment variables whose mere presence (with any non-empty value) signals a risk.
|
|
36
|
+
const RISKY_PRESENCE_VARS = [
|
|
37
|
+
"NODE_PATH",
|
|
38
|
+
"NODE_NO_WARNINGS",
|
|
39
|
+
"NODE_PENDING_DEPRECATION",
|
|
40
|
+
"UV_THREADPOOL_SIZE",
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
// Pattern to detect environment variables that likely contain credentials.
|
|
44
|
+
// Uses an end-of-string anchor ($) so that common system variables like
|
|
45
|
+
// SSH_AUTH_SOCK (ends with _SOCK) and __CF_USER_TEXT_ENCODING (ends with _ENCODING)
|
|
46
|
+
// are NOT flagged as false positives.
|
|
47
|
+
// `cred` is kept alongside `credential(?:s)?` to also catch short-form names like MY_CRED.
|
|
48
|
+
const CREDENTIAL_VAR_PATTERN =
|
|
49
|
+
/_(?:token|key|secret|pass(?:word)?|credential(?:s)?|cred|user|email|auth|session)$/i;
|
|
50
|
+
|
|
51
|
+
// Proxy variables — NO_PROXY is a bypass-list and should not trigger a finding on its own.
|
|
52
|
+
const PROXY_VARS = ["HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy"];
|
|
53
|
+
|
|
54
|
+
const PERMISSION_FLAG_PATTERNS = PERMISSION_FLAGS.map(
|
|
55
|
+
(f) => new RegExp(`${f.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`, "i"),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
export function auditEnvironment(env = process.env) {
|
|
59
|
+
const findings = [];
|
|
60
|
+
const nodeOptions = env.NODE_OPTIONS || "";
|
|
61
|
+
const cdxgenNodeOptions = env.CDXGEN_NODE_OPTIONS || "";
|
|
62
|
+
const hasPermission = PERMISSION_FLAG_PATTERNS.some((re) =>
|
|
63
|
+
re.test(nodeOptions),
|
|
64
|
+
);
|
|
65
|
+
const cdxgenHasPermission = PERMISSION_FLAG_PATTERNS.some((re) =>
|
|
66
|
+
re.test(cdxgenNodeOptions),
|
|
67
|
+
);
|
|
68
|
+
const cdxgenHasCodeExecutionRisk = CODE_EXECUTION_PATTERNS.some((re) =>
|
|
69
|
+
re.test(cdxgenNodeOptions),
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
if (cdxgenHasPermission) {
|
|
73
|
+
findings.push({
|
|
74
|
+
type: "environment-variable",
|
|
75
|
+
variable: "CDXGEN_NODE_OPTIONS",
|
|
76
|
+
severity: "high",
|
|
77
|
+
message:
|
|
78
|
+
"CDXGEN_NODE_OPTIONS enables Node.js permission flags. These flags can alter filesystem, network, environment, worker, or child-process access during cdxgen execution.",
|
|
79
|
+
mitigation:
|
|
80
|
+
"Remove permission-related flags from CDXGEN_NODE_OPTIONS unless they are explicitly required and reviewed for safety.",
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (cdxgenHasCodeExecutionRisk) {
|
|
85
|
+
findings.push({
|
|
86
|
+
type: "environment-variable",
|
|
87
|
+
variable: "CDXGEN_NODE_OPTIONS",
|
|
88
|
+
severity: "high",
|
|
89
|
+
message:
|
|
90
|
+
"CDXGEN_NODE_OPTIONS contains Node.js flags that can inject code, load arbitrary modules, read env files, or enable debugger attachment.",
|
|
91
|
+
mitigation:
|
|
92
|
+
"Unset CDXGEN_NODE_OPTIONS or remove flags such as --require, --import, --loader, --eval, --print, --inspect, or --env-file.",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// NODE_TLS_REJECT_UNAUTHORIZED=0 disables TLS verification; any other value is benign.
|
|
96
|
+
if (env.NODE_TLS_REJECT_UNAUTHORIZED === "0") {
|
|
97
|
+
findings.push({
|
|
98
|
+
type: "environment-variable",
|
|
99
|
+
variable: "NODE_TLS_REJECT_UNAUTHORIZED",
|
|
100
|
+
severity: "high",
|
|
101
|
+
message:
|
|
102
|
+
"TLS certificate verification is disabled globally (NODE_TLS_REJECT_UNAUTHORIZED=0). All HTTPS connections, including SBOM uploads, are vulnerable to interception.",
|
|
103
|
+
mitigation:
|
|
104
|
+
"Unset NODE_TLS_REJECT_UNAUTHORIZED or set it to '1'. Use a trusted CA bundle instead of bypassing verification.",
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
for (const varName of RISKY_PRESENCE_VARS) {
|
|
109
|
+
if (env[varName] != null && env[varName] !== "") {
|
|
110
|
+
const messages = {
|
|
111
|
+
NODE_PATH:
|
|
112
|
+
"NODE_PATH is set and may cause unexpected modules to be loaded, enabling module-resolution poisoning.",
|
|
113
|
+
NODE_NO_WARNINGS:
|
|
114
|
+
"NODE_NO_WARNINGS suppresses Node.js deprecation and security warnings, which may hide exploitable conditions.",
|
|
115
|
+
NODE_PENDING_DEPRECATION:
|
|
116
|
+
"NODE_PENDING_DEPRECATION may alter runtime behavior in ways that affect cdxgen's dependency resolution.",
|
|
117
|
+
UV_THREADPOOL_SIZE:
|
|
118
|
+
"UV_THREADPOOL_SIZE alters the libuv thread pool and may affect performance or mask resource-exhaustion attacks.",
|
|
119
|
+
};
|
|
120
|
+
findings.push({
|
|
121
|
+
type: "environment-variable",
|
|
122
|
+
variable: varName,
|
|
123
|
+
severity: varName === "NODE_PATH" ? "high" : "medium",
|
|
124
|
+
message:
|
|
125
|
+
messages[varName] ||
|
|
126
|
+
`${varName} is set and may affect module resolution or runtime behavior.`,
|
|
127
|
+
mitigation: `Unset ${varName} before processing untrusted repositories.`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// NODE_OPTIONS / CDXGEN_NODE_OPTIONS code-execution flags
|
|
133
|
+
if (nodeOptions) {
|
|
134
|
+
for (const pattern of CODE_EXECUTION_PATTERNS) {
|
|
135
|
+
if (pattern.test(nodeOptions)) {
|
|
136
|
+
findings.push({
|
|
137
|
+
type: "code-execution",
|
|
138
|
+
variable: "NODE_OPTIONS",
|
|
139
|
+
severity: "high",
|
|
140
|
+
message: `NODE_OPTIONS contains a code-execution flag matching '${pattern.source}'. Malicious code in the scanned repository may exploit this to run arbitrary commands.`,
|
|
141
|
+
mitigation: hasPermission
|
|
142
|
+
? "Remove the flag or tighten --allow-* scopes; code-execution flags can bypass permission-model boundaries."
|
|
143
|
+
: "Remove the flag before scanning untrusted repositories, or add --permission to enable the Node.js permission model.",
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (hasPermission && !env.CDXGEN_SECURE_MODE && !process.permission) {
|
|
148
|
+
findings.push({
|
|
149
|
+
type: "permission-misuse",
|
|
150
|
+
variable: "NODE_OPTIONS",
|
|
151
|
+
severity: "medium",
|
|
152
|
+
message:
|
|
153
|
+
"Permission flags are present in NODE_OPTIONS but the Node.js permission model is not active. The flags have no protective effect.",
|
|
154
|
+
mitigation:
|
|
155
|
+
"Run cdxgen with Node.js ≥20 and pass --permission on the command line, or remove the redundant flags.",
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// JVM option injection
|
|
161
|
+
for (const jvmVar of [
|
|
162
|
+
"MVN_ARGS",
|
|
163
|
+
"GRADLE_ARGS",
|
|
164
|
+
"BAZEL_ARGS",
|
|
165
|
+
"JAVA_TOOL_OPTIONS",
|
|
166
|
+
"JDK_JAVA_OPTIONS",
|
|
167
|
+
]) {
|
|
168
|
+
const jvmOptions = env[jvmVar] || "";
|
|
169
|
+
if (jvmOptions) {
|
|
170
|
+
for (const pattern of JVM_CODE_EXECUTION_PATTERNS) {
|
|
171
|
+
if (pattern.test(jvmOptions)) {
|
|
172
|
+
findings.push({
|
|
173
|
+
type: "code-execution",
|
|
174
|
+
variable: jvmVar,
|
|
175
|
+
severity: "high",
|
|
176
|
+
message: `${jvmVar} contains a JVM agent or module-bypass flag matching '${pattern.source}'. This may allow code injection into Java-based build tools invoked during SBOM generation.`,
|
|
177
|
+
mitigation: `Unset or sanitize ${jvmVar} before scanning Java/Kotlin/Scala projects.`,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Proxy interception — informational
|
|
185
|
+
const activeProxy = PROXY_VARS.find((v) => env[v] != null && env[v] !== "");
|
|
186
|
+
if (activeProxy) {
|
|
187
|
+
findings.push({
|
|
188
|
+
type: "network-interception",
|
|
189
|
+
variable: activeProxy,
|
|
190
|
+
severity: "low",
|
|
191
|
+
message: `An outbound proxy is configured via ${activeProxy}. Registry lookups, dependency downloads, and SBOM uploads will be routed through this proxy.`,
|
|
192
|
+
mitigation:
|
|
193
|
+
"Verify the proxy is trusted and uses TLS. Remove the variable if not required for this scan.",
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Credential exposure — detect any env var whose name follows a credential-naming convention.
|
|
198
|
+
for (const [varName, varValue] of Object.entries(env)) {
|
|
199
|
+
if (varValue && CREDENTIAL_VAR_PATTERN.test(varName)) {
|
|
200
|
+
findings.push({
|
|
201
|
+
type: "credential-exposure",
|
|
202
|
+
variable: varName,
|
|
203
|
+
severity: "low",
|
|
204
|
+
message: `${varName} matches a credential naming pattern and is set in the environment. Build tools or install scripts invoked during SBOM generation may read environment variables.`,
|
|
205
|
+
mitigation: `Unset ${varName} when scanning untrusted repositories. Prefer ephemeral, scoped CI credentials injected at the workflow step rather than inherited shell variables.`,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Running as root — skip inside official cdxgen container images, which run as root by design.
|
|
211
|
+
if (
|
|
212
|
+
typeof process.getuid === "function" &&
|
|
213
|
+
process.getuid() === 0 &&
|
|
214
|
+
env?.CDXGEN_IN_CONTAINER !== "true"
|
|
215
|
+
) {
|
|
216
|
+
findings.push({
|
|
217
|
+
type: "privilege",
|
|
218
|
+
variable: "UID",
|
|
219
|
+
severity: "high",
|
|
220
|
+
message:
|
|
221
|
+
"cdxgen is running as root (UID 0). Any code executed during SBOM generation—including package manager install hooks—will run with full system privileges.",
|
|
222
|
+
mitigation:
|
|
223
|
+
"Run cdxgen as a non-privileged user. Use a container or VM with a dedicated low-privilege account.",
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Debug mode leaks internal details
|
|
228
|
+
if (
|
|
229
|
+
["debug", "verbose"].includes(env.CDXGEN_DEBUG_MODE) ||
|
|
230
|
+
env.SCAN_DEBUG_MODE === "debug"
|
|
231
|
+
) {
|
|
232
|
+
findings.push({
|
|
233
|
+
type: "debug-exposure",
|
|
234
|
+
variable: "CDXGEN_DEBUG_MODE",
|
|
235
|
+
severity: "low",
|
|
236
|
+
message:
|
|
237
|
+
"Debug/verbose logging is enabled. Sensitive values such as API tokens, file paths, and build-tool output may appear in terminal output or log files.",
|
|
238
|
+
mitigation:
|
|
239
|
+
"Disable CDXGEN_DEBUG_MODE in production and ensure debug log files are not committed or shared.",
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Deno-specific checks
|
|
244
|
+
|
|
245
|
+
// DENO_CERT installs a custom TLS CA; combined with an outbound proxy this enables MITM attacks
|
|
246
|
+
// on SBOM uploads and registry lookups.
|
|
247
|
+
if (
|
|
248
|
+
env.DENO_CERT !== undefined &&
|
|
249
|
+
env.DENO_CERT !== null &&
|
|
250
|
+
env.DENO_CERT !== ""
|
|
251
|
+
) {
|
|
252
|
+
findings.push({
|
|
253
|
+
type: "environment-variable",
|
|
254
|
+
variable: "DENO_CERT",
|
|
255
|
+
severity: "high",
|
|
256
|
+
message:
|
|
257
|
+
"DENO_CERT is set to a custom TLS certificate authority. A custom CA combined with an outbound proxy can enable man-in-the-middle attacks on registry lookups and SBOM uploads.",
|
|
258
|
+
mitigation:
|
|
259
|
+
"Unset DENO_CERT unless you explicitly require a private CA bundle. Prefer the system trust store.",
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Deno live permission model: check whether shell execution is broadly granted.
|
|
264
|
+
// cdxgen legitimately needs --allow-run for specific build tools; unrestricted shell access
|
|
265
|
+
// (sh/bash/cmd/powershell being granted) is a strong signal that --allow-all or
|
|
266
|
+
// --allow-run without restrictions was used, which allows package manager hooks to execute
|
|
267
|
+
// arbitrary commands during SBOM generation.
|
|
268
|
+
if (
|
|
269
|
+
typeof globalThis.Deno !== "undefined" &&
|
|
270
|
+
typeof globalThis.Deno?.permissions?.querySync === "function"
|
|
271
|
+
) {
|
|
272
|
+
try {
|
|
273
|
+
const shellCmds =
|
|
274
|
+
globalThis.Deno.build?.os === "windows"
|
|
275
|
+
? ["cmd", "powershell"]
|
|
276
|
+
: ["sh", "bash"];
|
|
277
|
+
const shellAllowed = shellCmds.some(
|
|
278
|
+
(cmd) =>
|
|
279
|
+
globalThis.Deno.permissions.querySync({ name: "run", command: cmd })
|
|
280
|
+
.state === "granted",
|
|
281
|
+
);
|
|
282
|
+
if (shellAllowed) {
|
|
283
|
+
findings.push({
|
|
284
|
+
type: "permission-misuse",
|
|
285
|
+
variable: "DENO_PERMISSIONS",
|
|
286
|
+
severity: "high",
|
|
287
|
+
message:
|
|
288
|
+
"cdxgen is running under Deno with unrestricted shell execution (--allow-all or --allow-run without restrictions). Package manager scripts invoked during SBOM generation can execute arbitrary commands.",
|
|
289
|
+
mitigation:
|
|
290
|
+
"Replace --allow-all with granular --allow-run=<tool> flags. Only allow the specific build tools required for this scan.",
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
} catch {
|
|
294
|
+
// Deno.permissions.querySync may throw in restricted or future Deno environments; ignore silently.
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return findings;
|
|
299
|
+
}
|