Skip to content

Lock file integrity check detects stale .md source but not direct .lock.yml YAML tampering — permission escalation possible [Content truncated due to length] #26593

@szabta89

Description

@szabta89

Summary

check_workflow_timestamp_api.cjs validates that the .md source has not changed since compilation by comparing hash(.md frontmatter) against the hash stored in the gh-aw-metadata comment of the .lock.yml. It does not verify that the .lock.yml YAML content matches what the compiler would produce from the current .md. An attacker with repository write access can edit the .lock.yml directly — for example changing issues: read to issues: write, widening the network allowlist, or removing the AWF firewall container — while leaving the .md source and the frontmatter_hash comment unchanged. The tampered file passes all activation checks and the agent job runs with the elevated configuration. Confirmed at v0.68.1; the class of weakness was first noted in specs/workflow-lock-metadata-tampering-2026-02-14.md at v0.43.23 with status "Requires Validation".

Affected Area

Compiled workflow integrity boundary — the boundary between the .md source (author-controlled intent) and the .lock.yml (runtime-executed artifact). Specifically: actions/setup/js/check_workflow_timestamp_api.cjs and actions/setup/js/frontmatter_hash_pure.cjs.

Reproduction Outline

  1. Identify a compiled .lock.yml in a repository where you have write access (or a PR review path that does not diff .lock.yml carefully).
  2. Edit one line in the .lock.yml YAML body, e.g. change issues: readissues: write in the agent job's permissions block.
  3. Leave the # gh-aw-metadata: {"frontmatter_hash":"..."} comment line unchanged.
  4. Commit and push the tampered .lock.yml (the .md source is untouched).
  5. Trigger the workflow — check_workflow_timestamp_api.cjs computes hash(.md frontmatter) and compares it to the stored comment hash; both match, so stale_lock_file_failed = false.
  6. The agent job runs with the elevated permission (issues: write) with no runtime error or integrity failure.

Observed Behavior

stale_lock_file_failed remains false for a tampered .lock.yml when the .md source is unchanged. The frontmatter_hash embedded in the gh-aw-metadata comment is never recomputed against the .lock.yml YAML body. GitHub Actions' YAML parser silently ignores all comments, so the integrity metadata stored in comments provides no tamper evidence.

Expected Behavior

The activation check-lock-file step should detect that the .lock.yml YAML content no longer corresponds to what the compiler would produce from the current .md source, and fail the workflow with an integrity error.

Security Relevance

The precondition (repository write access) narrows exploitability, but PRs routinely include .lock.yml changes that reviewers may not scrutinize as carefully as the .md source. The documented model implies integrity guarantees ("validates declarative configuration artifacts", "Validate Lock File" activation step) that the current check does not provide. Beyond permission elevation, an attacker could widen network allowlists or remove the AWF firewall container — both meaningful security boundary changes invisible to the runtime check.

Suggested Mitigations

  1. Extend the hash to cover .lock.yml YAML content: Include the compiled YAML body (or a canonical recompilation of .md) in the integrity check, not just the .md frontmatter hash.
  2. Move integrity metadata to a verified YAML field: YAML comments are silently ignored; a top-level YAML field would at minimum survive round-trips and could be verified.
  3. Add PR-time recompilation CI check: Automatically recompile every modified .md and diff against the committed .lock.yml; fail the PR if any difference is found.
  4. Document the current trust model: Clarify that .lock.yml files require the same code-review scrutiny as .md files and that frontmatter_hash is currently advisory-only.

Additional Context

If this design is intentional (e.g., the hash is meant only as a staleness guard, not a full content integrity check), that assumption should be documented explicitly in the security model and architecture documentation so repository operators understand the current trust boundary.

gh-aw version: v0.68.1

Original finding: https://github.com/githubnext/gh-aw-security/issues/1847

Generated by File Issue · ● 244K ·

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions