Skip to content

ci: prevent command injection in release workflow - #14

Open
dinwwwh wants to merge 1 commit into
mainfrom
claude/release-workflow-injection
Open

dinwwwh wants to merge 1 commit into
mainfrom
claude/release-workflow-injection

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Sep 25, 2026

Copy link
Copy Markdown
Member

The release workflow substituted its workflow_dispatch inputs (version, tag) directly into shell scripts, so a crafted value could run arbitrary commands in the job that publishes to npm with provenance (id-token: write). The version check didn't help, because it ran after the substituted line had already executed. Inputs now reach the scripts only as environment variables, and both the version and the dist-tag are validated in the first step, before anything is installed, bumped or published.

Fixes

  • Crafted version or tag inputs no longer execute: no ${{ }} expression remains inside any run: script
  • Malformed or option-like dist-tags (e.g. x --registry=…) now fail the run immediately instead of reaching pnpm publish
  • Dist-tags must now start with a lowercase letter and contain only a-z, 0-9, ., _ or -

Testing

  • Ran the original and patched workflows side by side under act, with bump/changelog/publish commands replaced by argument printers. Valid inputs (stable, prerelease, explicit tag, every skip flag on/off) produce identical commands; payloads that executed on the original are rejected in the first step
  • zizmor: 3 template-injection findings → 0. actionlint and ESLint pass; the only remaining note is an intentionally unquoted $NO_GIT_CHECKS, so an empty value adds no argument

Pass workflow_dispatch inputs to shell scripts through env instead of
${{ }} substitution, and validate the npm dist-tag alongside the version
in the first step so a malformed tag fails before install or publish.
@pkg-pr-new

pkg-pr-new Bot commented Sep 25, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/uncheck@14

commit: c24de22

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • Inputs reach the shell only via env — version and tag are wired through env: (VERSION, TAG_INPUT, TAG, NO_GIT_CHECKS), and no ${{ }} expression remains inside any run: block, so the template-injection vector is closed.
  • Validation moved ahead of side effects — the version format check now runs first, so a malformed value can no longer execute before being rejected.
  • Dist-tag validated — ^[a-z][a-z0-9._-]*$ blocks option-like values (e.g. x --registry=…) before they can reach pnpm publish; the ${TAG_INPUT:-${PREID:-latest}} fallback preserves the previous tag || preid || 'latest' semantics.
  • Boolean skip flags — !inputs.skip_bump / !inputs.skip_changelog replace the string comparisons against github.event.inputs.*, which is type-correct for the declared boolean inputs.
  • Reduced output surface — only the tag output is emitted now; grep confirms no file references the removed major/minor/patch/preid/number outputs.

The $NO_GIT_CHECKS expansion is intentionally unquoted and only ever resolves to --no-git-checks or an empty string from a constant expression, so it adds no argument when unset and is not attacker-controlled. inputs at job-level env and step-level if is valid for workflow_dispatch, and BASH_REMATCH[5] is correctly populated because the negated =~ match still records capture groups.

Pullfrog  | View workflow run | Using DeepSeek Flash (default — pick a model for stronger reviews) | 𝕏

@codecov

codecov Bot commented Sep 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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