Skip to content

ci: prevent command injection in release workflow - #2080

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.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
orpc 4f66cbe Commit Preview URL

Branch Preview URL
Sep 25 2026, 02:19 AM

@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!

@codspeed

codspeed Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will degrade performance by 12.74%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 1 regressed benchmark
✅ 29 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
❌ octet stream 640.6 µs 734.1 µs -12.74%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing claude/release-workflow-injection (4f66cbe) with main (b050f30)

Open in CodSpeed

@pkg-pr-new

pkg-pr-new Bot commented Sep 25, 2026

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

npm i https://pkg.pr.new/@orpc/ai-sdk@2080

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@2080

@orpc/bun

npm i https://pkg.pr.new/@orpc/bun@2080

@orpc/client

npm i https://pkg.pr.new/@orpc/client@2080

@orpc/cloudflare

npm i https://pkg.pr.new/@orpc/cloudflare@2080

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@2080

@orpc/experimental-effect

npm i https://pkg.pr.new/@orpc/experimental-effect@2080

@orpc/evlog

npm i https://pkg.pr.new/@orpc/evlog@2080

@orpc/hibernation

npm i https://pkg.pr.new/@orpc/hibernation@2080

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@2080

@orpc/experimental-lock

npm i https://pkg.pr.new/@orpc/experimental-lock@2080

@orpc/experimental-msw

npm i https://pkg.pr.new/@orpc/experimental-msw@2080

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@2080

@orpc/next

npm i https://pkg.pr.new/@orpc/next@2080

@orpc/node

npm i https://pkg.pr.new/@orpc/node@2080

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@2080

@orpc/opentelemetry

npm i https://pkg.pr.new/@orpc/opentelemetry@2080

@orpc/pinia-colada

npm i https://pkg.pr.new/@orpc/pinia-colada@2080

@orpc/pino

npm i https://pkg.pr.new/@orpc/pino@2080

@orpc/publisher

npm i https://pkg.pr.new/@orpc/publisher@2080

@orpc/ratelimit

npm i https://pkg.pr.new/@orpc/ratelimit@2080

@orpc/server

npm i https://pkg.pr.new/@orpc/server@2080

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@2080

@orpc/swr

npm i https://pkg.pr.new/@orpc/swr@2080

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@2080

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@2080

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@2080

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@2080

commit: 4f66cbe

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

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 no longer reach run: scripts via ${{ }} — version and tag are passed through env (VERSION, TAG_INPUT), closing the template-injection path in the job that holds id-token: write.
  • Validation runs first — the new id: version step validates both the version and the dist-tag before checkout, install, bump or publish, so malformed or option-like tags fail fast instead of reaching pnpm publish.
  • Skip-flag conditions modernized — github.event.inputs.skip_* != 'true' replaced with typed !inputs.skip_* boolean checks.
  • Outputs pruned — unused major/minor/patch/preid/number step outputs removed; a validated tag output added.

I verified the validation script end-to-end (valid stable/prerelease/explicit-tag cases pass; x --registry=…, 1.0.0; rm -rf /, -foo and alpha.0 are rejected), confirmed BASH_REMATCH is populated after the negated =~ test, confirmed from GitHub's contexts reference that inputs.<name> preserves the boolean type for workflow_dispatch, and checked that nothing references the removed outputs or this workflow from elsewhere.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

This branch has not been deployed

No deployments
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