Skip to content

Scorecard's PinnedDependencies is wrong for lockfile-enforced repos — 79 alerts on _pathroot, inline pinning would break CI #674

Description

@hyperpolymath

Owner ruling 2026-08-27: raise this upstream; do not work around it. Recording the finding and the evidence so the position is documented and reproducible.

The conflict

OSSF Scorecard's PinnedDependenciesID flags uses: actions/checkout@v7.0.1 as unpinned. On metadatastician/_pathroot that produces 79 alerts (68 PinnedDependenciesID + 11 CodeQL actions/unpinned-tag) — 52% of the repo's 151 open alerts — and with code_scanning threshold all, every one of them blocks every PR.

But the repo is lockfile-enforced, and on such repos that ref is pinned.

Why the lockfile is strictly stronger than an inline SHA

.github/workflows/actions.lock records, per dependency:

'actions/attest-build-provenance@v4.2.2':
    ref: 'v4.2.2'
    commit: 'sha1-4d101475d8b20a2381f78447822ac1eab6504dd8'
    owner_id: 44036562
    repo_id: 760702757
    uses:
        - 'actions/attest@508db95dd578ae2727ebd6217d5ba78e4fbda05d'

An inline SHA gives you the commit only. The lockfile additionally binds:

field what it defends against inline SHA
commit tag repointing ✅ equivalent
owner_id / repo_id repo takeover / rename-squatting — a different repo reusing the same path ❌ not expressed
uses: transitive dependencies of composite actions ❌ cannot be expressed at all

So converting to inline SHAs reduces supply-chain coverage.

And it actively breaks the workflows

Measured previously on hypatia: inline-pinning 40 refs across 21 workflows produced

  • 14 workflows → startup_failure (0 on the parent commit) — the lockfile no longer matched, so they were rejected before any job started;
  • dtolnay/rust-toolchain dropped from 7 lockfile entries;
  • both required CodeQL contexts became phantom — a workflow that never starts never reports — so PRs read as BLOCKED with no failing check.

Reverting restored all of it. gh actions-lock also refuses a ref that no tag or branch contains ("a symbolic ref is required for the lockfile"), so inline-pinning a commit that is not tag-reachable removes it from the lockfile entirely.

Verified on _pathroot today: gh actions-lock --no-fix reports all 32 workflows valid, while Scorecard reports 68 unpinned dependencies for the same tree.

Position

Scorecard has no knowledge of actions.lock and evaluates the uses: string in isolation. For lockfile-enforced repositories its PinnedDependenciesID finding is factually wrong, and acting on it degrades security and breaks CI.

Not being worked around per the ruling — no threshold change, no dismissals, no inline pinning. The path is upstream: Scorecard should recognise .github/workflows/actions.lock and treat a ref it covers as pinned.

An upstream report is drafted and ready to file against ossf/scorecard on request.

Related: standards#655, _pathroot#18.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions