---
title: "ci-secure: close the critical CI attack vectors"
description: "Scan your GitHub Actions for the ten critical CI/CD attack vectors, each with a plain-English attacker scenario and a fix you review. Runs on your machine."
url: https://starsling.dev/ci-secure
canonicalUrl: https://starsling.dev/ci-secure
---

# Close critical attack vectors in GitHub Actions with /ci-secure

Install the agent skill to check your CI for ten critical attack vectors an outsider could exploit and fix them

Find the workflows an attacker could hijack, understand exactly how the attack works, and close the vulnerability before it is exploited.

MIT licensed. Runs on your machine under your own `gh` login. No StarSling account, no data sent to StarSling.

## Install

```sh
npx skills add starslingdev/skills
```

Then type `undefined` in your repository.

## What ci-secure does

**Deterministic scanning:** The scanner, not the LLM, decides what counts as a finding. It parses your workflow YAML locally with PyYAML and uploads nothing. The optional network calls go to GitHub, under your own `gh` login.

**Agent-powered fixes:** Your coding agent explains each finding as a plain-English attacker scenario, then applies the fixes you choose to your working tree for review.

## How it works

### 01. Scan every workflow

Run `/ci-secure` inside your repository.

The scanner reads every file under `.github/workflows` locally and checks it against the ten supported attack vectors.

### 02. Find exploitable paths

ci-secure reports only vulnerabilities that can give an outsider a path to a concrete compromise.

That can include executing malicious code with repository privileges, stealing secrets, gaining access to a write token, or poisoning an artifact your repository ships.

### 03. See the attacker's path

Each finding tells you:

- Which workflow is affected
- Where the vulnerability begins
- What input the attacker controls
- What the attacker could ultimately do

No rule IDs without context. No unexplained severity labels.

### 04. Fix what you choose

Select the findings you want to close. Each one closes with a focused workflow change, such as a changed trigger, a removed interpolation, a reduced token permission, or a re-pinned action SHA.

Your coding agent updates the affected workflow files and leaves the changes in your working tree for review. It never commits, pushes, or opens a pull request on its own.

## Ten critical GitHub Actions attacks

Critical exploit-chain checks only: this is not a comprehensive security audit.

Every vector below is backed by a named public incident or published security research.

### 1. Template injection

Attacker-controlled text, such as a pull request title or branch name, is inserted directly into a shell command and executed by the workflow.

Seen in the wild: Seen in incidents involving nx, elementary-data, and Ultralytics.

### 2. Fork code executed with privileges

A workflow triggered by an untrusted contribution checks out and runs code from an outsider's fork while holding repository privileges.

Platform mitigation: Since June 2026, actions/checkout's default refuses fork checkouts on privileged triggers, but a SHA- or patch-pinned checkout never receives that change, other untrusted event types sit outside it, and a manual git fetch bypasses it entirely.

Seen in the wild: Documented by GitHub Security Lab and seen in the Trivy incident.

### 3. Poisoned shared cache

Attacker-controlled code poisons a shared cache that is later restored and executed by a trusted workflow.

Platform mitigation: GitHub made fork-written caches read-only on github.com in June 2026; the path stays open on GitHub Enterprise Server, on third-party cache backends, and for poisoning from a trusted trigger that runs untrusted code.

Seen in the wild: Seen in incidents involving TanStack and Ultralytics.

### 4. Impostor action SHA

A workflow pins an action to a commit that never existed in the canonical repository, allowing the pin to resolve to attacker-controlled code.

Seen in the wild: Seen in the tj-actions incident and Chainguard's impostor-commit research.

### 5. Whole-context secrets dump

A workflow serializes its entire secrets context into logs or environment variables, exposing credentials to anything running in the job.

Seen in the wild: Seen in the tj-actions payload behavior disclosed in 2025.

### 6. GITHUB_ENV or GITHUB_PATH hijack

Attacker-controlled input is written into `GITHUB_ENV` or `GITHUB_PATH`, changing the environment or executable path for later steps.

Published research: Documented by GitHub Security Lab.

### 7. Write token on an untrusted trigger

A workflow grants write permissions to an event an outsider can trigger, causing attacker-controlled activity to run with repository write access.

Platform mitigation: GitHub shipped workflow-trigger policies in June 2026, but they are opt-in and evaluate-mode, so nothing changes on default configuration.

Seen in the wild: Seen in the elementary-data incident.

### 8. Credentials in caches or artifacts

Private keys or credential files are stored in caches or uploaded artifacts where other jobs, users, or the public may be able to retrieve them.

Seen in the wild: Documented in analysis of the Trivy cache compromise.

### 9. Unverified curl piped to bash

A workflow downloads and immediately executes a remote script without verifying it. If the remote host is compromised, the attacker gains execution inside your workflow.

Seen in the wild: Seen in the Codecov breach.

### 10. Dependency install scripts in a privileged job

A package you depend on is taken over and its install script runs the next time your workflow installs dependencies, inside a job holding secrets or a write token. The attacker never touches your repository; the script executes with the job's credentials before a single test has run.

Seen in the wild: Seen in the s1ngularity postinstall payloads in 2025 and the Miasma npm compromise in 2026.

## FAQ

### Is ci-secure a complete security audit?

No.

Critical exploit-chain checks only: this is not a comprehensive security audit.

ci-secure focuses specifically on ten critical GitHub Actions attack vectors that give an outsider a path to a concrete compromise.

Broader CI configuration and best-practice checks belong in [/ci-score](/ci-score).

### Does the LLM decide what counts as a vulnerability?

No.

The deterministic scanner decides whether a workflow matches one of the ten supported attack vectors. The coding agent explains the finding and applies the fix you choose.

### Does any of this reach StarSling?

No.

The scanner reads your workflow YAML locally, nothing is sent to StarSling, and you do not need a StarSling account to run it. The only optional network calls are GitHub lookups, one checking whether a pinned action SHA exists in the canonical repository and one reading a workflow's recent run history to tell you a finding sits in a dormant workflow, and both use your own `gh` CLI login.

### Will it modify my repository?

Only after you choose a finding to fix.

Changes are applied to your working tree for review. ci-secure never commits, pushes, or opens a pull request on its own.

### What happens when the scan finds nothing?

The report says zero findings.

It does not add lower-priority observations, inflate the result, or silently pass checks that could not run.

## Close the paths attackers could use to hijack your CI

Install the skill, run `/ci-secure`, and review any critical GitHub Actions vulnerability it finds before choosing what to fix.

## Resources

- [View the repository](https://github.com/starslingdev/skills)
- [Read the skill](https://github.com/starslingdev/skills/tree/main/skills/ci-secure)
