Skip to main content
RunBook Academy

Git, CI/CD & GitOpsLXVI · Third-Party Actions and PluginsRisk

Abandoned actions and the frozen actor

Advanced⏱ ~22 mingit

What you'll learn

  • Recognise that an unmaintained action is a security liability even though its code is unchanged
  • Identify the signals that indicate an action is no longer maintained
  • Distinguish an abandoned action from a stable action and the different risks each presents
  • Recognise the runner-image and transitive-dependency drift that an abandoned action cannot respond to

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

An abandoned action is an action whose maintainer has moved on. The action is not malicious; the action is unmaintained. The bytes the runner pulls do not change. The world around the bytes does: new CVEs in transitive dependencies, new runner images with new system libraries, deprecated endpoints in the APIs the action calls. The frozen action becomes a frozen attack surface, and no one patches it because no one is home.

What “abandoned” actually means

An action is abandoned when the maintainer has stopped responding to:

  • Security advisories. A CVE is published against the action or its transitive dependencies. The maintainer is the only person who can publish a patched release.
  • Dependency updates. A widely-used package ships a security fix. The action’s package.json references the old version.
  • API changes. The cloud provider deprecates an endpoint the action calls.
  • Compatibility changes. GitHub ships a new runner image with a new Node version. The action’s pinned Node is unsupported.
flowchart LR
    A["Day 1 - action published"] --> B["Runner image v1"]
    A --> C["Dependency version v1"]
    A --> D["API version v1"]
    E["Day 600 - maintainer gone"] --> F["Runner image v47"]
    E --> G["Dependency v1 still installed"]
    E --> H["API v1 deprecated"]
    F -. "new CVEs" .-> G
    F -. "no patches" .-> H

The action is unchanged. The action’s environment is not. The gap is where the security debt accumulates.

The signals of abandonment

Five signals indicate abandonment risk: (1) no commits in 12 months; (2) open issues with no response for months; (3) no release in 18 months; (4) transitive dependencies pinned to old versions; (5) maintainer account inactive. None is conclusive alone, but together they paint a picture of an action with no one left to fix it. The distinguishing test is responsiveness: an abandoned action does not respond to security reports within a reasonable window.

Why pinning to a SHA does not help

Pinning to a SHA closes the tag-swap attack. Pinning does not close the abandonment gap. The pinned SHA still resolves to the same bytes. The same bytes still depend on the same vulnerable transitive packages and still call the same deprecated APIs. The bytes are immutable; the environment is not.

Distinguishing abandoned from stable

Three patterns look like abandonment but are not:

  • Feature-complete mature projects. A linter, parser, or transformer. The project has converged; the lack of commits is the goal.
  • Versioned stable branches. The maintainer commits to main regularly but treats v1.x.x as a frozen LTS branch.
  • Vendor-owned projects with batch updates. A cloud vendor publishes quarterly releases; the action appears unmaintained between batches.

The distinguishing test is responsiveness. A stable action’s maintainer responds even if the response is “triaged, not patching”.

Production discipline

  1. Maintain an action inventory. List every third-party action with the maintainer, last commit, last release, and pin. Review quarterly.
  2. Set a deprecation threshold. No commits in 18 months, no release in 24 months, and an unresponsive maintainer means the action is deprecated.
  3. Prefer vendor-owned actions for vendor-specific work. aws-actions/*, azure/*, google-github-actions/* are first-party to their vendors.
  4. Audit transitive dependency age at pin time. An action pinning ^1.0.0 of a dependency that is now ^4.0.0 upstream is at risk of breaking on the next major release.
  5. Plan a fork as a fallback. Fork the action into your own organisation, vendor the dependencies, and maintain the fork internally. The fork is first-party.

Cross-course references

  • Git, CI/CD & GitOps — Part LXVI-03 (Supply-Chain Attack) covers the malicious-maintainer case.
  • Git, CI/CD & GitOps — Part LXVI-05 (Pinning to SHA) covers the immutable-reference defence.
  • Git, CI/CD & GitOps — Part LXV-05 (Artifact Trust) covers the content-addressing model.
  • Linux for Production Sysadmins — Part XXIV (Package Security) covers the system-level analogue.

Quiz

Knowledge check · 4 questions

  1. Q1. What is the security risk of an abandoned third-party action that has not been updated in two years?

  2. Q2. Pinning to a SHA fully protects a consumer workflow from an abandoned action.

  3. Q3. Name two of the five signals that indicate an action is at risk of abandonment.

  4. Q4. Identify the abandonment indicators in the action and the rule that closes the risk.

    Team T uses `individual-maintainer/deploy-helper@v2`, pinned by tag. The action's last commit was 22 months ago; last release 26 months ago. The action's `package.json` references `node-fetch@^1.0.0` (current major is `^3.0.0`). The maintainer's profile shows no activity in 18 months. Two CVEs against `node-fetch@^1.0.0` were published in the last six months; no patched release of `deploy-helper` has shipped.

Passing score: 75%. Answers are checked in this browser.