Skip to content

fix(scan): stop go-shell-exec-command reporting a fully literal argv - #158

Merged
ralyodio merged 1 commit into
masterfrom
go-shell-constant-argv
Aug 17, 2026
Merged

fix(scan): stop go-shell-exec-command reporting a fully literal argv#158
ralyodio merged 1 commit into
masterfrom
go-shell-constant-argv

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

exec.Command("cmd", "/c", "ver") reads the Windows version. It does re-introduce a shell — which is what the rule says — but there is nothing in the argv for anyone to reach, so the metacharacters the consequence warns about are metacharacters nobody can supply. gosec's G204 draws the line in the same place: constant arguments are not the finding.

Where it came from

This was the entire output of a whole-repository scan of SibtainOcn/Quiesce, a local Windows CLI in Go. One finding, and it was this one:

// ui.go:199
out, err := exec.Command("cmd", "/c", "ver").Output()

The maintainer had already declined the scan workflow on the grounds that the classes ThreatCrush targets have no surface in that codebase. He was right down to the single line. With this guard the repository scans clean, which is the honest result rather than a quieter wrong one.

The guard

A lineGuard, so it only reads the matched line — the exemption must not become a window-wide amnesty.

It ends at the closing paren, which is what keeps it narrow. A literal followed by anything else still reports:

still flagged why the guard misses it
exec.Command("sh", "-c", "ping -c 1 "+host) a + before the )
exec.Command("sh", "-c", fmt.Sprintf("ping %s", host)) an identifier before the )
exec.Command("sh", "-c", command) a bare name before the )

Escaped quotes inside a literal are consumed rather than read as the end of one, so exec.Command("bash", "-c", "echo \"hi\"") does not fall out of the guard on a technicality.

Verification

  • 323 tests pass across the whole packages/scan suite.
  • New cover in false-positives.test.ts pairs three shapes that must go quiet with three that must still fire — a fix that only silences is indistinguishable from deleting the rule.
  • Run against the real ui.go from Quiesce: [].

🤖 Generated with Claude Code

`exec.Command("cmd", "/c", "ver")` reads the Windows version. It does
re-introduce a shell, which is what the rule says, but there is nothing in
the argv for anyone to reach — the metacharacters the consequence warns
about are metacharacters nobody can supply. gosec's G204 draws the line in
the same place: constant arguments are not the finding.

This was the entire output of a whole-repository scan of SibtainOcn/Quiesce,
a local Windows CLI in Go. One finding, and it was this one. The maintainer
declined the scan workflow on the grounds that the classes it targets have
no surface in that codebase, and he was right down to the single line.
With the guard the repository scans clean, which is the honest result.

The guard has to end at the closing paren so that a literal followed by
anything else still reports: `"ls " + dir` leaves a `+`, `fmt.Sprintf(…)`
leaves an identifier, a bare variable leaves a name. Escaped quotes inside
a literal are consumed rather than treated as the end of one, so
`"echo \"hi\""` does not fall out of the guard on a technicality.

323 tests pass. Both halves are covered: three shapes that must go quiet
and three that must still fire.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

ThreatCrush Security Scan

63 finding(s)

HIGH/CRITICAL: 4 | MEDIUM: 52 | LOW: 7

Severity Rule Location
HIGH secret-aws-access-key prd/0003-detect-hardcoded-secrets-before-they-are-committed-or-served.md:126
HIGH sh-eval-expansion .githooks/pre-commit:26
HIGH sh-remote-script-execution apps/web/public/install.sh:272
HIGH sh-remote-script-execution apps/web/public/install.sh:320
MEDIUM insecure-temp-file .githooks/commit-msg:16
MEDIUM insecure-temp-file .githooks/post-commit:20
MEDIUM js-shell-exec-interpolation apps/cli/src/commands/init.ts:70
MEDIUM js-shell-exec-interpolation apps/cli/src/commands/init.ts:79
MEDIUM js-shell-exec-interpolation apps/cli/src/commands/service.ts:92
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:31
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:33
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:34
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:35
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:36
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:43
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:49
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:56
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:63
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:82
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:84
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:85
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:93
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:98
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:105
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:112
MEDIUM js-shell-exec-interpolation apps/cli/src/index.ts:425
MEDIUM js-unescaped-html-sink apps/web/src/app/about/page.tsx:180
MEDIUM js-unescaped-html-sink apps/web/src/app/about/page.tsx:184
MEDIUM js-open-redirect apps/web/src/app/auth/login/page.tsx:50
MEDIUM js-unescaped-html-sink apps/web/src/app/blog/[slug]/page.tsx:125
MEDIUM js-unescaped-html-sink apps/web/src/app/blog/[slug]/page.tsx:153
MEDIUM js-unescaped-html-sink apps/web/src/app/blog/[slug]/page.tsx:157
MEDIUM js-unescaped-html-sink apps/web/src/app/get-whitepaper/page.tsx:346
MEDIUM js-unescaped-html-sink apps/web/src/app/layout.tsx:211
MEDIUM js-unescaped-html-sink apps/web/src/app/layout.tsx:215
MEDIUM js-unescaped-html-sink apps/web/src/app/layout.tsx:219
MEDIUM js-unescaped-html-sink apps/web/src/app/page.tsx:120
MEDIUM js-unescaped-html-sink apps/web/src/app/store/[slug]/page.tsx:86
MEDIUM js-open-redirect apps/web/src/components/funding/FundingClient.tsx:97
MEDIUM manifest-install-lifecycle-script package.json:24
MEDIUM js-uninitialized-buffer packages/scan/src/node-rules.ts:456
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/apt.ts:154
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/apt.ts:160
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/apt.ts:208
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/apt.ts:313
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/aur.ts:256
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/chocolatey.ts:264
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/chocolatey.ts:288
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/rpm.ts:201
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/rpm.ts:261

…and 13 more. Full results in the Security tab.

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio merged commit 4f0982c into master Aug 17, 2026
11 checks passed
ralyodio added a commit to profullstack/sh1pt that referenced this pull request Aug 17, 2026
…ers (#971)

0.11.3 carries two false-positive fixes that reach nobody on a pinned pack
until this moves — which is the standing property this pack documents about
itself, not a surprise.

- go-shell-exec-command no longer fires on a fully literal argv
  (profullstack/threatcrush#158). `exec.Command("cmd", "/c", "ver")` has
  nothing in it for anyone to influence; gosec's G204 draws the same line.
- js-uninitialized-buffer no longer fires on a buffer filled before use
  (#156).

Spec and integrity bumped in the same edit, as the input's own description
requires: a hash from a different version fails closed, which is the right
direction to fail and a confusing one to debug.

The hash is npm's `dist.integrity` for 0.11.3, verified independently rather
than copied — the published tarball was downloaded and hashed, and
`openssl dgst -sha512 | openssl base64` reproduces it byte for byte:

  sha512-lxWvTtLDgckiWlRB3wMSoBNfMZ/3ao0CcmwETGyKclc+5NMU5Pl0jXSr0h+QrTtfxh7TNStk4ZgP5h8xbEvIWw==

Verified against the published package rather than a local build: installed
@profullstack/threatcrush@0.11.3 from the registry and re-scanned. Quiesce,
the Go CLI whose single finding motivated #158, now reports 0. The
malware-test-prs fixtures still report all 43 criticals, so detection has
not moved.

README's documented default moved with the manifest so the two cannot
disagree. The 1.6.0/0.11.0 anecdote further down is left alone; it is
accurate history and it is the reason this pack explains the lag at all.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant