From f36462cec279b5ec7bfbcd98076c9e58effd2b66 Mon Sep 17 00:00:00 2001 From: PunGrumpy <108584943+PunGrumpy@users.noreply.github.com> Date: Sun, 12 Jul 2026 20:29:28 +0700 Subject: [PATCH 1/3] fix(core): support space-separated ENV KEY VALUE in noSecretsInEnv --- packages/core/src/rules/security.ts | 88 +++++++++++++++++++---------- 1 file changed, 57 insertions(+), 31 deletions(-) diff --git a/packages/core/src/rules/security.ts b/packages/core/src/rules/security.ts index 4e93163..ceaa5a7 100644 --- a/packages/core/src/rules/security.ts +++ b/packages/core/src/rules/security.ts @@ -58,38 +58,64 @@ export const noSecretsInEnv: DockerfileRule = { for (const inst of instructions) { if (inst.instruction === "ENV" || inst.instruction === "ARG") { - const parts = inst.args.split(/\s+/u); - // ENV can be KEY=VALUE or KEY VALUE - for (const part of parts) { - const eqIndex = part.indexOf("="); - let key = ""; - let value = ""; - - if (eqIndex > 0) { - key = part.slice(0, eqIndex); - value = part.slice(eqIndex + 1); - } else { - // Might be ENV KEY VALUE - key = part; + const args = inst.args.trim(); + if (inst.instruction === "ENV" && !args.includes("=")) { + // KEY VALUE format + const match = args.match(/^(?[^\s]+)\s+(?.*)$/u); + if (match?.groups) { + const { key, value } = match.groups; + const isSecretKey = secretKeywords.some((regex) => regex.test(key)); + if ( + isSecretKey && + value && + !value.startsWith("$") && + !value.startsWith("{") + ) { + diagnostics.push( + createDiagnostic( + file, + this.key, + this.defaultSeverity as "error" | "warning" | "info", + `Potential secret found in ${inst.instruction}: '${key}'. Secrets baked into images can be extracted easily by anyone with image access.`, + this.help, + inst.line + ) + ); + } } - - const isSecretKey = secretKeywords.some((regex) => regex.test(key)); - if ( - isSecretKey && - value && - !value.startsWith("$") && - !value.startsWith("{") - ) { - diagnostics.push( - createDiagnostic( - file, - this.key, - this.defaultSeverity as "error" | "warning" | "info", - `Potential secret found in ${inst.instruction}: '${key}'. Secrets baked into images can be extracted easily by anyone with image access.`, - this.help, - inst.line - ) - ); + } else { + // Existing KEY=VALUE logic + const parts = args.split(/\s+/u); + for (const part of parts) { + const eqIndex = part.indexOf("="); + let key = ""; + let value = ""; + + if (eqIndex > 0) { + key = part.slice(0, eqIndex); + value = part.slice(eqIndex + 1); + } else { + key = part; + } + + const isSecretKey = secretKeywords.some((regex) => regex.test(key)); + if ( + isSecretKey && + value && + !value.startsWith("$") && + !value.startsWith("{") + ) { + diagnostics.push( + createDiagnostic( + file, + this.key, + this.defaultSeverity as "error" | "warning" | "info", + `Potential secret found in ${inst.instruction}: '${key}'. Secrets baked into images can be extracted easily by anyone with image access.`, + this.help, + inst.line + ) + ); + } } } } From 1fd2f3425c4a4f369cff8701314d9c3ee8ed5e7d Mon Sep 17 00:00:00 2001 From: PunGrumpy <108584943+PunGrumpy@users.noreply.github.com> Date: Sun, 12 Jul 2026 20:44:33 +0700 Subject: [PATCH 2/3] test(core): add space-separated format test cases for noSecretsInEnv --- packages/core/test/rules.test.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/core/test/rules.test.ts b/packages/core/test/rules.test.ts index d73c21c..36c3317 100644 --- a/packages/core/test/rules.test.ts +++ b/packages/core/test/rules.test.ts @@ -62,6 +62,21 @@ describe("Security Rules", () => { `); const diags = noSecretsInEnv.check(withSecret, "Dockerfile"); expect(diags).toHaveLength(1); + + const withSpaceSecret = parseDockerfile(` + ENV DB_PASSWORD my-secret-pass + `); + const diagsSpace = noSecretsInEnv.check(withSpaceSecret, "Dockerfile"); + expect(diagsSpace).toHaveLength(1); + + const withSpaceNormal = parseDockerfile(` + ENV NORMAL_VAR my-value + `); + const diagsSpaceNormal = noSecretsInEnv.check( + withSpaceNormal, + "Dockerfile" + ); + expect(diagsSpaceNormal).toHaveLength(0); }); }); From ec27cd864e86dbd784a04661477981cef6809ab9 Mon Sep 17 00:00:00 2001 From: PunGrumpy <108584943+PunGrumpy@users.noreply.github.com> Date: Sun, 12 Jul 2026 20:58:06 +0700 Subject: [PATCH 3/3] chore(repo): add changeset for noSecretsInEnv fix --- .changeset/fix-env-secret-format-parsing.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fix-env-secret-format-parsing.md diff --git a/.changeset/fix-env-secret-format-parsing.md b/.changeset/fix-env-secret-format-parsing.md new file mode 100644 index 0000000..111fa50 --- /dev/null +++ b/.changeset/fix-env-secret-format-parsing.md @@ -0,0 +1,5 @@ +--- +"@docker-doctor/cli": patch +--- + +Fix `no-secrets-in-env` rule to support space-separated `ENV KEY VALUE` format, ensuring hardcoded credentials in this format are correctly detected by the linter.