Fix: reject malformed/truncated ${{ secrets. expressions in processExpressions#18171
Merged
Fix: reject malformed/truncated ${{ secrets. expressions in processExpressions#18171
${{ secrets. expressions in processExpressions#18171Conversation
Add a guard in processExpressions that rejects content containing a partial
${{ secrets. pattern (e.g. ${{ secrets.TOKEN }T with missing }}) that bypasses
the well-formed expression regex. Also add fuzz corpus entry 9661e56aa0ec2781
to prevent regression.
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix truncated secrets expression handling in fuzz job
Fix: reject malformed/truncated Feb 24, 2026
${{ secrets. expressions in processExpressions
pelikhan
approved these changes
Feb 24, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a security vulnerability where malformed or truncated ${{ secrets. expressions bypass validation in processExpressions. The fuzzer discovered that expressions like ${{ secrets.TOKEN }T (missing closing }}) were not caught because the regex only matched well-formed ${{ ... }} blocks.
Changes:
- Added early validation check to detect partial
${{ secrets.patterns before they bypass the main expression regex - Added fuzz corpus entry to prevent regression of this specific vulnerability
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
actions/setup/js/runtime_import.cjs |
Adds security guard to detect and reject malformed/truncated secrets expressions that bypass the well-formed expression regex |
pkg/parser/testdata/fuzz/FuzzRuntimeImportProcessExpressions/9661e56aa0ec2781 |
Adds minimized fuzz corpus entry reproducing the vulnerability to prevent future regressions |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
processExpressionsonly matched well-formed${{ ... }}blocks via regex, so a truncated expression like${{ secrets.TOKEN }T(missing}}) produced zero matches and returned the original content as safe. The fuzz harness caught this because its invariant check (/\$\{\{[^}]*secrets\./) correctly flags such inputs as security violations.Changes
actions/setup/js/runtime_import.cjs— After computingmatches, add a guard using/\$\{\{[^}]*secrets\./. If that pattern is present incontentbut none of the well-formed captures (m[1]) containsecrets., throwERR_VALIDATIONimmediately. Well-formed${{ secrets.X }}expressions remain handled by the existingisSafeExpressionpath.pkg/parser/testdata/fuzz/FuzzRuntimeImportProcessExpressions/9661e56aa0ec2781— Adds the minimized corpus entry (Secret: ${{ secrets.TOKEN }T) that reproduces the fuzz failure, pinning the invariant against regression.Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
https://api.github.com/graphql/usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw -test.run=^Test -test.short=trueHEAD git rev-�� --show-toplevel resolved$ /usr/bin/unpigz -json GO111MODULE x_amd64/vet /usr/bin/unpigz(http block)https://api.github.com/repos/actions/ai-inference/git/ref/tags/v1/usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha -unreachable=false l 3978800/b389/vet.cfg d7ab9ec12dbe903egit GO111MODULE 64/bin/go /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet -uns�� -unreachable=false /tmp/go-build1583978800/b263/vet.cfg ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet -json GO111MODULE 64/bin/go ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v3/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha 374/001/stability-test.md 81c88388fc5569beec7cf4cb:go.mod ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v4 --jq .object.sha g_.a GO111MODULE /opt/hostedtoolcache/go/1.25.0/x-buildmode=exe GOINSECURE GOMOD GOMODCACHE /opt/hostedtoolcache/go/1.25.0/x-extld=gcc -uns�� sAOsG8WsF /tmp/go-build1583978800/b057/vet.cfg 0/x64/bin/node GOSUMDB GOWORK 64/bin/go /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v4 --jq .object.sha 76 GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet -uns�� runs/20260224-153838-27546/test-3934205799/.github/workflows /tmp/go-build1583978800/b104/vet.cfg 0/x64/bin/node l GOWORK 64/bin/go /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v4 --jq .object.sha --show-toplevel go 6786/001/go/1.25.0/x64/bin/go -json GO111MODULE x_amd64/vet git conf�� user.name Test User /usr/bin/git ub/workflows GO111MODULE x_amd64/vet git(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v5/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha 932779234/.github/workflows .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env -json .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha se 3978800/b110/vet.cfg /usr/bin/git -errorsas -ifaceassert -nilfunc git -C /tmp/compile-instructions-test-3629014071/.github/workflows rev-parse /usr/bin/git --check **/*.cjs 64/bin/go git(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel x_amd64/vet 3978800/b433/vet.cfg b/workflows GO111MODULE x_amd64/vet git rev-�� --show-toplevel x_amd64/vet /tmp/go-build1583978800/b431/workflow.test -json GO111MODULE x_amd64/vet /tmp/go-build1583978800/b431/workflow.test(http block)https://api.github.com/repos/actions/github-script/git/ref/tags/v8/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha npx prettier --cGOSUMDB GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go sh -c "prettier" --check 'scripts/**/*GOINSECURE node 64/bin/go tierignore ../../../pkg/wor-atomic 64/bin/go go(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha k/gh-aw/gh-aw/pk-errorsas k/gh-aw/gh-aw/pk-ifaceassert 64/bin/go **/*.json --ignore-path ../../../.pretti-unreachable=false /opt/hostedtoolc/tmp/go-build1583978800/b265/vet.cfg -o /tmp/go-build1481836524/b400/_pkGOINSECURE -trimpath 64/bin/go -p main -lang=go1.25 go(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha prettier --check 64/bin/go --ignore-path .prettierignore 64/bin/go go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/actions/setup-go/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet -uns�� runs/20260224-153838-27546/test-2152807819/.github/workflows /tmp/go-build1583978800/b067/vet.cfg 3978800/b336/vet.cfg GOSUMDB GOWORK 64/bin/go /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/actions/setup-node/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha tutil.test GO111MODULE ortcfg.link GOINSECURE GOMOD GOMODCACHE xLPGO5v5ZsAOsG8WsF/788KaSlanoh1QIKEP8dB/iAJz33n4qBSgoBRlrikz -uns�� -unreachable=false /tmp/go-build1583978800/b051/vet.cfg g_.a GOSUMDB GOWORK 64/bin/go /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/github/gh-aw/actions/runs/1/artifacts/usr/bin/gh gh run download 1 --dir test-logs/run-1 GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/github/gh-aw/actions/runs/12345/artifacts/usr/bin/gh gh run download 12345 --dir test-logs/run-12345 GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env ub/workflows .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/github/gh-aw/actions/runs/12346/artifacts/usr/bin/gh gh run download 12346 --dir test-logs/run-12346 GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env ub/workflows .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linutest@example.com(http block)https://api.github.com/repos/github/gh-aw/actions/runs/2/artifacts/usr/bin/gh gh run download 2 --dir test-logs/run-2 GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/github/gh-aw/actions/runs/3/artifacts/usr/bin/gh gh run download 3 --dir test-logs/run-3 GO111MODULE x_amd64/link GOINSECURE GOMOD GOMODCACHE x_amd64/link env -json .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE HC/wPHmRHH07drGotDxh6_4/9rUbv3kNVNgnGPLEQds7(http block)https://api.github.com/repos/github/gh-aw/actions/runs/4/artifacts/usr/bin/gh gh run download 4 --dir test-logs/run-4 GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/github/gh-aw/actions/runs/5/artifacts/usr/bin/gh gh run download 5 --dir test-logs/run-5 GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/github/gh-aw/actions/workflows/usr/bin/gh gh workflow list --json name,state,path prettier --check 64/bin/go **/*.ts **/*.json --ignore-path go env -json GOMOD 64/bin/go tierignore format:cjs 64/bin/go go(http block)/usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 100(http block)/usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 6 GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linutest@example.com(http block)https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.0.0/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha -json rty 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env -json .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/nonexistent/action/git/ref/tags/v999.999.999/usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha y-test.md GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env 4165525112/.github/workflows .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/nonexistent/repo/actions/runs/12345/usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env -json .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/owner/repo/actions/workflows/usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go **/*.ts **/*.json --ignore-path go list�� -mod=readonly -f 64/bin/go -- unsafe 64/bin/go go(http block)/usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go **/*.ts **/*.json --ignore-path git stat�� --porcelain sh 64/bin/go npx prettier --w/opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/owner/repo/contents/file.md/tmp/go-build1583978800/b381/cli.test /tmp/go-build1583978800/b381/cli.test -test.testlogfile=/tmp/go-build1583978800/b381/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true GOINSECURE GOMOD GOMODCACHE npx pret�� --check scripts/**/*.js 64/bin/go .prettierignore GOWORK 64/bin/go go(http block)https://api.github.com/repos/test-owner/test-repo/actions/secrets/usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name prettier --check 64/bin/go **/*.ts **/*.json --ignore-path go env GOPATH node 64/bin/go -d format:cjs 64/bin/go go(http block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.