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

Closed as not planned

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: read → issues: 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 · ◷

Activity

  1. pelikhan commented on Apr 16, 2026

    @pelikhan
    Collaborator

    Editing lock.yml is a common way to work around our issues. This is by design.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions