> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pipefort.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Rules overview

> Fifty checks across CI/CD platforms: GitHub Actions workflows, GitHub repository configuration, and GitLab CI.

Pipefort runs deterministic checks per scan across three surfaces:

* **23 GitHub Actions workflow checks** parse `.github/workflows/*.yml`.
* **17 GitHub repository-configuration checks** call the GitHub API for branch protection, default workflow permissions, secret scanning, and Dependabot.
* **10 GitLab CI workflow checks** parse `.gitlab-ci.yml` and `.gitlab-ci/**/*.yml`.

Workflow checks cover **all ten** [OWASP CI/CD Top 10](https://owasp.org/www-project-top-10-ci-cd-security-risks/) categories (CICD-SEC-1 through CICD-SEC-10) on both platforms.

## GitLab CI workflow checks

The GitLab rule IDs are parallel to the GitHub ones — same OWASP category,
different IDs (e.g. `cicd-sec-1-gl-mr-target` for the merge-request-target
analog of `cicd-sec-1-ppe-checkout`). Findings tagged `-gl-` only fire on
`.gitlab-ci.yml` / `.gitlab-ci/*.yml`. The two structural rules
`best-prac-1-pipe-to-shell` and `cicd-sec-9-download-without-checksum`
share their ID across both platforms.

| Category    | GitLab rule ID                     | Severity | Auto-fix |
| ----------- | ---------------------------------- | -------- | -------- |
| CICD-SEC-1  | `cicd-sec-1-gl-mr-target`          | HIGH     | ✗        |
| CICD-SEC-2  | `cicd-sec-2-gl-pat-secret`         | MEDIUM   | ✗        |
| CICD-SEC-3  | `cicd-sec-3-gl-unpinned-include`   | MEDIUM   | ✗        |
| CICD-SEC-4  | `cicd-sec-4-gl-shell-injection`    | HIGH     | ✗        |
| CICD-SEC-6  | `cicd-sec-6-gl-hardcoded-secrets`  | HIGH     | ✗        |
| CICD-SEC-7  | `cicd-sec-7-gl-debug-trace`        | HIGH     | ✓        |
| CICD-SEC-8  | `cicd-sec-8-gl-trigger-unfiltered` | MEDIUM   | ✗        |
| CICD-SEC-10 | `cicd-sec-10-gl-allow-failure`     | LOW      | ✓        |
| BEST-PRAC-2 | `best-prac-2-gl-missing-timeout`   | LOW      | ✓        |
| BEST-PRAC-3 | `best-prac-3-gl-self-hosted-tags`  | LOW      | ✗        |

### v1 limitations

* `include:` graph traversal is not performed — the scanner inspects only
  the literal `.gitlab-ci.yml` and `.gitlab-ci/*.yml` contents, not files
  referenced from another project or URL.
* Project-side settings (Protected Branches, Push rules, Secret Detection)
  are not audited yet. The GitHub equivalent of these audits is shipped;
  GitLab project settings are on the roadmap.

Rules carry **framework tags** so they can be filtered by the standard they
serve: [OWASP Top 10 CI/CD Security Risks](https://owasp.org/www-project-top-10-ci-cd-security-risks/)
and the [SLSA v1.2 specification](https://slsa.dev/spec/v1.2/) (Build and
Source tracks). A single rule can belong to multiple frameworks.

## Workflow file checks

| Category                                                        | Title                                                                       | Severity | Auto-fix |
| --------------------------------------------------------------- | --------------------------------------------------------------------------- | -------- | -------- |
| [CICD-SEC-1](/rules/cicd-sec-1)                                 | Dangerous checkout in `pull_request_target` / `workflow_run`                | HIGH     | ✓        |
| [CICD-SEC-1](/rules/cicd-sec-1-workflow-run-artifact-poisoning) | `workflow_run` downloads artifacts from the triggering run                  | HIGH     | ✗        |
| [CICD-SEC-1](/rules/cicd-sec-1-checkout-persist-credentials)    | Checkout persists credentials under a privileged trigger                    | MEDIUM   | ✓        |
| [CICD-SEC-2](/rules/cicd-sec-2)                                 | Long-lived personal access token                                            | MEDIUM   | ✗        |
| [CICD-SEC-3](/rules/cicd-sec-3)                                 | Unpinned third-party action                                                 | MEDIUM   | ✓        |
| [CICD-SEC-4](/rules/cicd-sec-4)                                 | Poisoned Pipeline Execution (shell injection)                               | HIGH     | ✓        |
| [CICD-SEC-4](/rules/cicd-sec-4-secrets-inherit-pr-target)       | Reusable workflow called with `secrets: inherit` under a privileged trigger | HIGH     | ✗        |
| [CICD-SEC-5](/rules/cicd-sec-5)                                 | Missing permissions specification                                           | MEDIUM   | ✓        |
| [CICD-SEC-6](/rules/cicd-sec-6)                                 | Hardcoded credentials                                                       | HIGH     | ✓        |
| [CICD-SEC-6](/rules/cicd-sec-6-secret-in-run-output)            | Secret printed to logs or written to step output                            | HIGH     | ✗        |
| [CICD-SEC-7](/rules/cicd-sec-7)                                 | Actions debug logging enabled in workflow                                   | HIGH     | ✓        |
| [CICD-SEC-8](/rules/cicd-sec-8)                                 | `repository_dispatch` trigger without `types:` allowlist                    | MEDIUM   | ✗        |
| [CICD-SEC-9](/rules/cicd-sec-9)                                 | Downloaded artifact has no integrity check                                  | MEDIUM   | ✗        |
| [CICD-SEC-10](/rules/cicd-sec-10)                               | Job-level `continue-on-error` suppresses failure visibility                 | LOW      | ✓        |
| [BEST-PRAC-1](/rules/best-prac-1)                               | Command piped directly to shell                                             | HIGH     | ✗        |
| [BEST-PRAC-2](/rules/best-prac-2)                               | Job timeout not configured                                                  | LOW      | ✓        |
| [BEST-PRAC-3](/rules/best-prac-3)                               | Self-hosted runner usage                                                    | LOW      | ✗        |
| [SLSA-BUILD-L2](/rules/slsa-build-l2-provenance)                | Build provenance is not generated                                           | HIGH     | ✗        |
| [SLSA-BUILD-L2](/rules/slsa-build-l2-oidc-token-scope)          | Provenance/signing step missing `id-token: write`                           | MEDIUM   | ✓        |
| [SLSA-BUILD-L2](/rules/slsa-build-l2-perms-overly-broad)        | Permissions block overly broad                                              | HIGH     | partial  |
| [SLSA-BUILD-L2](/rules/slsa-build-l2-verify-step)               | Workflow consumes artifacts without verifying provenance                    | INFO     | ✗        |
| [SLSA-BUILD-L3](/rules/slsa-build-l3-provenance-isolated)       | Provenance generated in-job (not isolated)                                  | MEDIUM   | ✗        |
| [SLSA-BUILD-L3](/rules/slsa-build-l3-cache-poisoning)           | Cache key in `pull_request_target` from PR-controlled input                 | HIGH     | ✗        |

## Repository configuration checks

These read GitHub-side settings and surface under a "Repository configuration" group in the UI (CLI: `<repository settings>` file label). They need the expanded GitHub App permissions described in [GitHub App permissions](/concepts/github-app-permissions); the CLI needs `--github-token` (or `$GITHUB_TOKEN`, or `gh auth token`).

### Branch protection (CICD-SEC-1)

| Rule                                                                 | Title                                                        | Severity | Auto-fix |
| -------------------------------------------------------------------- | ------------------------------------------------------------ | -------- | -------- |
| [BP-MISSING](/rules/cicd-sec-1-bp-missing)                           | Default branch has no branch protection rule                 | **HIGH** | ✓        |
| [BP-FORCE-PUSH](/rules/cicd-sec-1-bp-force-push)                     | Default branch allows force pushes                           | **HIGH** | ✓        |
| [BP-DELETION](/rules/cicd-sec-1-bp-deletion)                         | Default branch can be deleted                                | HIGH     | ✓        |
| [BP-NO-REVIEW](/rules/cicd-sec-1-bp-no-review)                       | Default branch does not require pull request reviews         | **HIGH** | ✗        |
| [BP-FEW-REVIEWERS](/rules/cicd-sec-1-bp-few-reviewers)               | Default branch requires fewer than 2 approving reviews       | MEDIUM   | ✗        |
| [BP-STALE-REVIEWS](/rules/cicd-sec-1-bp-stale-reviews)               | Default branch does not dismiss stale reviews on new commits | MEDIUM   | ✗        |
| [BP-NO-STATUS-CHECKS](/rules/cicd-sec-1-bp-no-status-checks)         | Default branch does not require status checks to pass        | MEDIUM   | ✗        |
| [BP-ADMIN-BYPASS](/rules/cicd-sec-1-bp-admin-bypass)                 | Admins can bypass branch protection                          | **HIGH** | ✓        |
| [BP-NO-CODEOWNERS-REVIEW](/rules/cicd-sec-1-bp-no-codeowners-review) | CODEOWNERS exists but their review is not required           | LOW      | ✓        |
| [BP-NO-SIGNED-COMMITS](/rules/cicd-sec-1-bp-no-signed-commits)       | Default branch does not require signed commits               | LOW      | ✓        |

### Actions runtime (CICD-SEC-4, CICD-SEC-5)

| Rule                                                         | Title                                                 | Severity | Auto-fix |
| ------------------------------------------------------------ | ----------------------------------------------------- | -------- | -------- |
| [WPERM-WRITE](/rules/cicd-sec-4-wperm-write)                 | Default GITHUB\_TOKEN permissions are read-write      | **HIGH** | ✓        |
| [WPERM-PR-APPROVE](/rules/cicd-sec-4-wperm-pr-approve)       | GitHub Actions can approve pull requests              | **HIGH** | ✓        |
| [ACTIONS-ALL-ALLOWED](/rules/cicd-sec-5-actions-all-allowed) | All GitHub Actions and reusable workflows are allowed | MEDIUM   | ✗        |

### Dependency hygiene (CICD-SEC-3)

| Rule                                                             | Title                                    | Severity | Auto-fix |
| ---------------------------------------------------------------- | ---------------------------------------- | -------- | -------- |
| [DEPENDABOT-ALERTS-OFF](/rules/cicd-sec-3-dependabot-alerts-off) | Dependabot alerts are disabled           | MEDIUM   | ✓        |
| [DEPENDABOT-FIXES-OFF](/rules/cicd-sec-3-dependabot-fixes-off)   | Dependabot security updates are disabled | LOW      | ✓        |

### Credential hygiene (CICD-SEC-6)

| Rule                                                                       | Title                                       | Severity | Auto-fix |
| -------------------------------------------------------------------------- | ------------------------------------------- | -------- | -------- |
| [SECRET-SCANNING-OFF](/rules/cicd-sec-6-secret-scanning-off)               | Secret scanning is disabled                 | MEDIUM   | ✓        |
| [SECRET-PUSH-PROTECTION-OFF](/rules/cicd-sec-6-secret-push-protection-off) | Secret-scanning push protection is disabled | **HIGH** | ✓        |

Auto-fix on repo-settings rules is powered by the CLI's `--fix-settings` flag and the web app's per-finding **Fix** button — see [Auto-fix](/cli/auto-fix#repository-configuration-auto-fix-fix-settings).

## Rulesets

The CLI's `--ruleset` flag (and the web app's ruleset selector) controls which checks contribute to the final list. Filtering is by **framework membership**, not by category prefix — see [SLSA framework overview](/rules/slsa-overview) for a rule-by-rule mapping.

* **`all`** (default) — every check listed above.
* **`owasp`** — every rule tagged with the OWASP framework.
* **`slsa`** — every rule tagged with any SLSA v1.2 framework (Build *or* Source).
* **`slsa-build-l1`** / **`slsa-build-l2`** / **`slsa-build-l3`** — rules for that specific Build level (and only that level — to find every rule a repo needs to satisfy L3, run with `slsa` and look at the heatmap).
* **`slsa-source-l2`** / **`slsa-source-l3`** / **`slsa-source-l4`** — rules for that specific Source level. (L1 is "Version Controlled" — trivially satisfied for any GitHub repo.)

## Enabling and disabling individual rules

The web app lets you toggle any individual rule on or off without changing the
ruleset — per user, with optional per-repository overrides. See
[Rule settings](/webapp/rule-settings) for the model and the UI. The CLI's
filtering is limited to the coarser `--ruleset` choice above; multi-tenant
preferences depend on the database and are web-only.

## How the checks run

Each workflow check is a function that takes the parsed workflow YAML AST and returns a list of findings. The CLI and the web app both invoke the same `ScanBytes(name, content)` entrypoint.

Repository-configuration checks are a separate pass: the API client first fetches the relevant GitHub settings (`FetchRepositorySettings`) and then runs `ScanRepositorySettings(context)` to produce findings. These findings carry a synthetic file path (`<repository settings>`) and a zero line/column so consumers can render them apart from per-file findings.

See [Auto-fix](/cli/auto-fix) for which workflow categories the CLI's `--fix` flag rewrites. Repository-configuration findings have no auto-fix — they're flagged for manual remediation via GitHub's UI.
