← October 2026
App Idea Cards 2026-10-02

Pinwatch

A CLI and GitHub Action that keeps checking your SHA-pinned GitHub Actions after the scan is over, and catches it when the tag behind a pin gets quietly repointed or a fork-triggered job can poison a…

Pinwatch

Pinwatch

A CLI and GitHub Action that keeps checking your SHA-pinned GitHub Actions after the scan is over, and catches it when the tag behind a pin gets quietly repointed or a fork-triggered job can poison a cache a privileged job later trusts.

Problem

Pinning a third-party action to a commit SHA is the standard fix for tag-repointing attacks like tj-actions/changed-files (CVE-2025-30066), where 23,000+ repos running @v45 got hit because a tag is just a mutable pointer. Tools like zizmor catch the unpinned case at scan time. But the SHA comment next to the pin, uses: owner/repo@a1b2c3d # v4.2.0, is only true the day someone writes it. Nothing re-checks it six months later, and nothing watches for the attack TanStack hit on May 11, 2026: a pull_request_target workflow let a forked PR poison a shared Actions cache, which a separate, privileged release workflow then restored and trusted, letting the attacker extract an OIDC token straight out of runner memory and publish 84 malicious npm packages without ever touching a maintainer's credentials.

Target user

Platform and security engineers at npm/PyPI-publishing orgs or internal monorepos running dozens of GitHub Actions workflows. This is the team that already adopted zizmor or actionlint after the 2026 wave of supply-chain incidents (TanStack in May, keyv in August, the Microsoft-documented ChainDrop worm), and wants to know what those linters stop checking once the scan is done.

MVP scope

  • Parse every .github/workflows/*.yml file and extract all uses: owner/repo@<sha> # <tag> pins
  • Daily scheduled Action that re-resolves each tag against the GitHub API and diffs the commit it now points to against the SHA recorded in the comment, opening an Issue (never a silent auto-PR) for any pin whose comment no longer matches reality
  • Build a reachability graph per repo: flag any job triggered by pull_request_target, workflow_run, or a fork-writable event that shares a cache key (actions/cache, setup-node cache, etc.) with a job holding id-token: write or secrets access. That's the exact TanStack chain.
  • SARIF output so findings land in GitHub code scanning next to CodeQL and zizmor results instead of a separate dashboard
  • Single-binary CLI plus a drop-in composite Action (pinwatch init scaffolds the scheduled workflow)
  • A reviewed-pin allowlist so a deliberate, human-approved tag bump doesn't re-trigger the same alert every day

Monetization

Freemium. The CLI and single-repo scheduled scan are free and open source (MIT). The paid tier is a hosted dashboard that ingests results across every repo in a GitHub org, tracks pin-drift trends over time, and pushes Slack/PagerDuty alerts. Priced flat per org per month, aimed at the platform-security team that owns the org, not billed per seat.

Why now

The TanStack compromise on May 11, 2026 showed that SHA pinning alone doesn't stop a cache-poisoning path between a fork-triggered job and a privileged one. The GitHub Actions hardening checklist published this year recommends SHA pinning but, by its own account, doesn't cover monitoring for retroactive tag repoints or cache-key collisions across workflows. That's the gap Pinwatch closes, continuously instead of once at scan time.

Risks & open questions

  • Demand-side: teams that already run zizmor or Dependabot may assume they're covered and won't see the gap until it's explained with a real incident, which is a hard sell before a breach
  • Cache-key resolution is the hard engineering problem: keys are often built from templated context expressions that are difficult to resolve statically across workflow boundaries
  • Daily re-resolution of every pin across every workflow in a large org risks hitting GitHub's secondary API rate limits without a careful ETag/conditional-request layer
  • Legitimate tag movement under a moving major version (@v4 bumping from v4.1 to v4.2) will look identical to a malicious repoint unless the allowlist flow is low-friction enough that teams actually use it

Next step

Build the SHA-vs-tag drift checker first against a sample of real public repos' workflow history to measure false-positive rate before investing in the harder cache-reachability graph.

Sources

More from App Idea Cards