Back to Cheat Sheets

🔌 Ungoverned Usage of 3rd Party Services

OWASP Top 10 CI/CD Security Risks - CICD-SEC-8

HIGH RISK

📋 What Is It?

Ungoverned Usage of 3rd Party Services is the risk that arises when your CI/CD ecosystem depends on a large number of external services and integrations - third-party SCM Apps, OAuth grants, marketplace CI plugins, reusable Actions authored by strangers, SaaS tools wired in through tokens and webhooks, and bots - granted access to your source, build systems, and secrets with little to no governance. It is not a single vulnerability in your code; it is the accumulated, unmonitored trust you have extended to third parties whose security posture you neither control nor observe. Access is granted quickly and broadly but rarely inventoried, scoped down, reviewed, or revoked.

CICD-SEC-8 OWASP Rank
Trust Focus Area
Transitive Blast Radius

⚠️ Common Exploits

  • Over-Scoped App / OAuth: Org-wide read/write granted "to be safe"
  • Mutable Action Tags: @v2 / @main repointed to malicious code after adoption
  • Compromised SaaS in Build: A trusted uploader/scanner tampered upstream
  • Stolen Integration Token: A vendor's OAuth token used to clone your private repos
  • Typosquat / Takeover: Lookalike or hijacked marketplace component
  • Long-Lived Vendor Token: Broad PAT stored on a third party's servers, no expiry
  • Stale / Forgotten Grants: Deploy keys and bots from finished projects still active

🔴 Attack Flow

1. Identify the trust (Apps, tokens, Actions, bots)
↓
2. Compromise or abuse it (breach vendor, hijack tag)
↓
3. Execute in runner or call API with its access
↓
4. Harvest source + secrets, pivot to cloud
↓
5. IMPACT: Mass secret harvest across a vendor's customer base!

❌ Vulnerable Code

# .github/workflows/build.yml - ungoverned third-party usage jobs: build: runs-on: ubuntu-latest steps: - uses: some-user/awesome-action@v2 ← mutable tag, unknown author - uses: another/deploy-step@main ← HEAD of a repo you don't control env: # Long-lived broad PAT handed to a SaaS tool and stored on ITS servers COVERAGE_TOKEN: ghp_************************ ← "repo" scope, no expiry # uploader script fetched fresh each run - tampering upstream runs in YOUR job - run: bash <(curl -s https://cdn.thirdparty.example/uploader.sh) # App authorized "to be safe" - one click grants everything, never reviewed permissions: repositories: all ← every repo in the org contents: read-write ← a read-only scanner asking for write members: read webhooks: read-write ← can add its own persistence # Org settings: any Action in the world may run, anyone may install any App allowed_actions: all

✅ Secure Code

# .github/workflows/build.yml - governed third-party usage permissions: id-token: write # mint short-lived OIDC per run, no stored PAT contents: read jobs: build: runs-on: ubuntu-latest steps: # Pin every third-party step to a full commit SHA (immutable), version in comment - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: some-user/awesome-action@3f1c0a9d6b2e4f8a1c7d5e2b9f0a4c6d8e1b3a5c # v2.3.1 - uses: vendor/coverage-uploader@9f8e7d6c5b4a39281706f5e4d3c2b1a0f9e8d7c6 # v4.2.0 with: { use-oidc: true } # temporary, upload-only credential # App scoped to exactly what the stated feature requires permissions: repositories: [web-app] ← only the repo it serves contents: read ← read-only scanner => read only pull_requests: read owner: dev-experience-team review_by: 2026-07-10 ← access expires unless re-justified # Org policy: allow-list of components, deny by default, admin approval to install allowed_actions: selected allow: ["actions/*@*", "our-org/*@*", "verified-vendor/tool@9f8e7d6..."] deny_by_default: true

✓ Prevention Checklist

  • Maintain an inventory of every App, OAuth, token, webhook, bot
  • Give each integration a named owner and reason to exist
  • Require approval + security review to onboard a new integration
  • Grant least-privilege scopes: specific repos, read-only where possible
  • Prefer short-lived OIDC credentials over stored PATs
  • Pin all third-party Actions/plugins to a full commit SHA
  • Restrict which Actions/apps may run via org allow-list
  • Verify inbound webhook signatures; minimize outbound data
  • Review access on a schedule; revoke stale/unused grants
  • Tie integration ownership to the offboarding process
  • Log and alert on third-party activity
  • Assume the third party is breached; limit blast radius

🔍 Detection & Tools

Governance & Pinning:

Dependabot / Renovate (SHA pins) StepSecurity Harden-Runner OpenSSF Scorecard Org allowed-actions policy pinact / ratchet

Identity & Monitoring:

OIDC short-lived tokens SCM audit logs HMAC webhook verification OAuth-app / installed-app review

How to Test:

  • List all authorized OAuth apps, Apps, deploy keys, and webhooks
  • Reconcile that list against a documented inventory
  • Grep workflows for mutable refs (@v1, @main, @master)
  • Check for stored long-lived PATs vs. OIDC federation
  • Confirm the org restricts which Actions/apps may run
  • Verify unsigned inbound webhooks are rejected

🌍 Real-World Incident Classes

  • Compromised CI/CD SaaS uploader (Codecov-class): A widely used tool that runs inside customers' pipelines had a distribution mechanism tampered with; because customers handed it access to the build environment, it could read env vars and secrets - a single third party became a mass secret-harvesting event across its customer base.
  • OAuth token abuse against SCM repos: Attackers obtained tokens issued to popular third-party integrations and used them to clone the private repositories of organizations that had authorized those integrations - the token became a skeleton key.
  • Malicious or hijacked marketplace component: A component is malicious from the start (a name resembling a trusted one) or a legitimate one whose maintainer account is taken over and whose tag is repointed to malicious code; pipelines referencing a moving tag executed it on their next run.

Note: these are documented, repeatedly-observed classes; vendor names are used only where the pattern is publicly and widely associated with them. No invented figures are presented - the durable takeaway is that at least one third party you trust will eventually be breached.

📌 Quick Tips

  • DO NOT reference Actions by mutable tag or branch
  • DO NOT grant org-wide read/write "to be safe"
  • DO NOT store long-lived broad PATs with vendors
  • DO pin components to full commit SHAs
  • DO inventory and own every integration
  • DO allow-list which components may run
  • DO review and revoke stale grants on a schedule

📜 Compliance

Related Standards:

  • SLSA Supply-chain integrity levels
  • NIST SSDF / 800-161 Supply Chain
  • SOC 2 CC9.2 - Vendor & third-party risk
  • ISO 27001 A.15 - Supplier Relationships
  • OpenSSF Secure Supply Chain (S2C2F)