Reusable Workflow Secrets Inheritance

Description

When one workflow calls a reusable workflow, it can forward credentials with secrets: inherit. This passes all of the caller’s secrets to the called workflow with no per-secret control. 1 The called workflow — which may live in another repository, be maintained by a different team, or be updated independently — then has access to the caller’s complete secret store, widening the blast radius of any vulnerability or compromise in that downstream workflow. Explicitly naming the secrets a reusable workflow requires keeps each credential scoped to where it is genuinely needed. This complements Excessive Secret Exposure, which concerns bulk serialization within a single workflow.

Vulnerable Instance

  • A job calls a reusable workflow via uses: and forwards credentials with secrets: inherit.
  • The reusable workflow receives every secret available to the caller, not just the ones it needs.
name: Release
on: [push]
jobs:
  publish:
    uses: ./.github/workflows/publish.yml
    secrets: inherit   # forwards ALL caller secrets downstream

Mitigation Strategies

  1. Pass only the required secrets, explicitly by name Declare each secret the reusable workflow needs and forward just those.

    jobs:
      publish:
        uses: ./.github/workflows/publish.yml
        secrets:
          REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
  2. Declare inputs in the reusable workflow Have the reusable workflow define a workflow_call block with explicit secrets: entries so callers cannot accidentally over-share.

  3. Audit cross-repository reuse Be especially careful when the reusable workflow lives in a different repository or is maintained by another team; inherit exposes your secrets to code you do not directly control.

  4. Prefer short-lived credentials Where possible, have the reusable workflow obtain its own short-lived tokens via OIDC instead of receiving long-lived secrets from the caller.

Secure Version

 name: Release
 on: [push]
 jobs:
   publish:
     uses: ./.github/workflows/publish.yml
-    secrets: inherit
+    secrets:
+      REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}

Impact

DimensionSeverityNotes
LikelihoodMediumsecrets: inherit is convenient and widely used, often without considering how many secrets it forwards.
RiskMediumA vulnerability or compromise in the called workflow gains access to every secret the caller holds.
Blast radiusWideAll caller secrets become reachable by the downstream workflow, which may be externally maintained.

References


Last updated on