fix: lock-file integrity check now covers compiled YAML body#24157
Closed
fix: lock-file integrity check now covers compiled YAML body#24157
Conversation
Add a `compiled_hash` field to the lock file metadata that covers all non-comment YAML lines. The runtime integrity check in `check_workflow_timestamp_api.cjs` now verifies this hash in addition to the existing frontmatter hash. This detects tampering with security-critical fields (permissions, env vars, job steps, network policies) in the compiled lock file even when the .md source is unchanged. - Go: add `CompiledHash` to `LockMetadata`, compute it via two-pass generation in `generateYAML` after emitting the YAML body, then inject it into the `gh-aw-metadata` comment - JS: add `extractCompiledHashFromLockFile` and `computeCompiledHashFromLockFile` to `frontmatter_hash_pure.cjs` - JS: verify compiled hash in `check_workflow_timestamp_api.cjs`; fail with a tamper-detection message on mismatch - Old lock files without `compiled_hash` continue to work (backward compatible; only frontmatter hash is checked) - All 179 repo lock files recompiled with the new field Agent-Logs-Url: https://github.com/github/gh-aw/sessions/95b17fcc-94fe-4d93-b174-4789a4505521 Co-authored-by: szabta89 <1330202+szabta89@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix lock-file integrity check to cover compiled YAML content
fix: lock-file integrity check now covers compiled YAML body
Apr 2, 2026
Collaborator
|
Hash is a staleness measure, not a tampering preventionechanism |
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.
The runtime integrity check validated only the
.mdfrontmatter hash, leaving the compiled YAML body unprotected. An actor with repo write access could modifypermissions:,--allow-domains,GITHUB_READ_ONLY, or--allowed-toolsin a.lock.ymlwhile leaving the# gh-aw-metadata:comment untouched — the check would pass and the agent would run with tampered config.Approach
Two-pass compilation (Go): After generating the full YAML, compute SHA-256 of all non-comment lines and inject it as
compiled_hashinto the existinggh-aw-metadataJSON comment. Because the metadata line is itself a comment, it's excluded from the hash — no chicken-and-egg problem.Runtime verification (JS):
check_workflow_timestamp_api.cjsre-strips comment lines from the fetched lock file content and recomputes the hash. Mismatch fails with a🚨 Tamper Detectedsummary.Changes
pkg/workflow/lock_schema.go— addcompiled_hash(omitempty) toLockMetadatapkg/workflow/compiler_yaml.go— addcomputeCompiledHash()andinjectCompiledHashIntoMetadata(); call both aftergenerateWorkflowBody()when a frontmatter hash existsactions/setup/js/frontmatter_hash_pure.cjs— addextractCompiledHashFromLockFile()andcomputeCompiledHashFromLockFile()actions/setup/js/check_workflow_timestamp_api.cjs— verify compiled hash in both the API and local-filesystem code paths; compiled hash mismatch is checked before frontmatter hash to surface tamper attempts earlyBackward compatibility
Lock files without
compiled_hash(compiled by older tooling) continue to pass — only the frontmatter hash is checked, with a log note that the compiled hash check was skipped.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 origin/fallback-/home/REDACTED/.npm/_npx/b388654678d519d9/node_modules/.bin/prettier odules/npm/node_--write 0/x64/bin/node ve h ../../../.pret.prettierignore tions/setup/js/n--log-level=error 0/x64/bin/bash -errorsas -ifaceassert -nilfunc tions/setup/js/node_modules/vite-buildtags(http block)/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 origin/fallback-/home/REDACTED/.npm/_npx/b388654678d519d9/node_modules/.bin/prettier 64/bin/git 0/x64/bin/node ve h ../../../.pret.prettierignore tions/setup/js/n--log-level=error de -errorsas -ifaceassert -nilfunc tions/setup/js/node_modules/vite-trimpath(http block)/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 origin/fallback--c t 0/x64/bin/node ve h ../../../.prettierignore tions/setup/js/node_modules/vitest/suppress-warnings.cjs ndor/bin/bash -errorsas -ifaceassert -nilfunc tions/setup/js/node_modules/vite-trimpath(http block)https://api.github.com/orgs/test-owner/actions/secrets/usr/bin/gh gh api /orgs/test-owner/actions/secrets --jq .secrets[].name -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE 3k6c8jM/KCvsvKYw-buildtags(http block)/usr/bin/gh gh api /orgs/test-owner/actions/secrets --jq .secrets[].name -goversion go1.25.0 -c=4 -race -nolocalimports -importcfg /tmp/go-build760040655/b225/importcfg ache�� 64/src/os/user rtcfg x_amd64/compile 040655/b125/ go /usr/bin/git x_amd64/compile(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 --show-toplevel go /usr/bin/git ub/workflows GO111MODULE 64/bin/go git rev-�� --show-toplevel go /usr/bin/infocmp -json GO111MODULE x_amd64/link infocmp(http block)/usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha sistency_KeyOrdering862459076/001/test1.md x_amd64/vet /usr/bin/gh ay_c1201377758/0git -I x_amd64/vet gh run view 12345 /usr/bin/git nonexistent/repogit --json status,conclusio--show-toplevel git(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 7224277/b442/_pkg_.a go 0/x64/bin/node ck '**/*.cjs' '*git GO111MODULE 64/bin/go 0/x64/bin/node push�� CxFj/4N_hV3O2Cg4KalLpCxFj my-default /usr/bin/git -json GO111MODULE 64/bin/go git(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha /tmp/go-build760040655/b321/_pkg_.a l /usr/bin/git -p golang.org/x/oaurev-parse -lang=go1.24 /usr/bin/git remo�� -v -buildid /usr/bin/git -goversion go1.25.0 -c=4 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 -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE ache/go/1.25.0/x64/bin/go GOINSECURE s $k => $v) echorev-parse GOMODCACHE go(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha xterm-color x_amd64/vet /usr/bin/git -json GO111MODULE x_amd64/link git rev-�� --show-toplevel x_amd64/link /usr/bin/git -json GO111MODULE ache/go/1.25.0/x--show-toplevel git(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel go /usr/bin/git ithub/workflows GO111MODULE 64/pkg/tool/linu--show-toplevel git rev-�� --show-toplevel 64/pkg/tool/linux_amd64/vet 0/x64/bin/node 7224277/b417/loggit GO111MODULE 7224277/b417/imp--show-toplevel git(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v6/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel sh r,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,disp--show-toplevel "prettier" --chegit flow 64/bin/go git init�� 0:00Z go /usr/bin/git -json GO111MODULE 64/bin/go git(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel ortcfg /usr/bin/git 138061221 GO111MODULE ache/go/1.25.0/x--show-toplevel git rev-�� --show-toplevel ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet /usr/bin/git -json GO111MODULE e/git git(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 -json GO111MODULE 64/bin/go GOINSECURE GOMOD erignore go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE node /opt�� prettier --check 64/bin/go **/*.ts **/*.json --ignore-path golangci-lint(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE sh -c "prettier" --che-r GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go git(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 uts.branch -goversion /usr/bin/git -c=4 -nolocalimports -importcfg git conf�� --get remote.origin.url /usr/bin/git -json GO111MODULE 64/bin/go git(http block)/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha sistency_GoAndJavaScript644444288/001/test-frontmatter-with-env-template-expressions.md x_amd64/vet /usr/bin/git 040655/b073/_pkggit -I x_amd64/vet git rev-�� --show-toplevel x_amd64/vet /usr/bin/gh ache/go/1.25.0/xgit 64/src/net x_amd64/vet gh(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 64/bin/go sh /usr/bin/git "prettier" --chegit sh 64/bin/go git conf�� --get remote.origin.url /opt/hostedtoolcache/node/24.14.0/x64/bin/node -json GO111MODULE 64/bin/go node(http block)/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha ithub/workflows/archie.md status /usr/bin/git .github/workflowgit 040655/b125/ x_amd64/compile git rev-�� --git-dir x_amd64/compile /usr/bin/git yX0PmxH/fojbNvvGgit rtcfg x_amd64/vet /usr/bin/git(http block)https://api.github.com/repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b/usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq .object.sha -bool -buildtags modules/@npmcli/run-script/lib/node-gyp-bin/sh -errorsas -ifaceassert -nilfunc /opt/hostedtoolcache/node/24.14.0/x64/bin/node --ex�� js/**/*.json' --ignore-path ../../../.prettierignore ser:token@github.com/repo.git.url tions/setup/js/node_modules/.bin/sh node --conditions development ache/go/1.25.0/x64/pkg/tool/linux_amd64/compile(http block)https://api.github.com/repos/github/gh-awDe-C k/gh-aw/gh-aw/ac/home/REDACTED/work/gh-aw/gh-aw/.github/workflows k/gh-aw/gh-aw/acrev-parse rev-�� nonexistent-branch-that-does-not-exist git r: $owner, name: $name) {
hasDiscussionsEnabled
}
} -1 96249d8c x_amd64/vet /opt/hostedtoolcmcp/memory` (http block)