> ## 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.

# Attacker Mind & toxic combinations

> How Pipefort correlates individual findings into higher-impact attack chains.

Most scanners grade each finding in isolation. But real compromises are rarely a
single misconfiguration — an attacker **chains** several. A
`pull_request_target` workflow that checks out untrusted code is risky on its
own; combine it with a writable `GITHUB_TOKEN` and it becomes a full repository
takeover.

**Attacker Mind** is Pipefort's correlation layer. It looks across the findings
from a scan and reports **toxic combinations**: named attack scenarios that
exist only when a *set* of findings co-occur. Each combination carries:

* a **severity** — `CRITICAL` or `HIGH` (toxic combinations sit *above* the
  per-finding severity scale, because the chained impact exceeds any single
  ingredient);
* an **attack chain** — the ordered stages of the compromise, so you can see
  what the attack actually looks like;
* the **contributing findings** with their `file:line` locations; and
* a **break-the-chain** recommendation — the single highest-leverage fix that
  collapses the whole scenario.

## How detection works

Combinations are pure correlation over findings that the scanner already
produced, so the same engine powers both the [CLI](/cli/usage) and the
[web dashboard](/webapp/attacker-mind). Combinations are matched on **rule IDs**
(not OWASP categories), because a category like `CICD-SEC-4` is emitted by more
than one rule (workflow shell-injection *and* the read-write `GITHUB_TOKEN`
repository setting) — matching on rule ID keeps each ingredient precise.

A combination only forms from findings that survived your
[rule settings](/webapp/rule-settings): if you disable a rule, it can never be
an ingredient.

Combinations are scoped:

* **file-scoped** combinations require their anchor ingredient inside one
  workflow file and are reported once per such file;
* **repo-scoped** combinations correlate across the whole repository and are
  reported once.

## The shipped combinations

| Combination                              | Severity | Ingredients (rule IDs)                                                                                                                                                                                                                                     | Breaks when you…                                                            |
| ---------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| **Pwn Request**                          | CRITICAL | `cicd-sec-1-ppe-checkout` + a writable token (`cicd-sec-5-missing-permissions` or `cicd-sec-4-wperm-write`); amplified by `cicd-sec-4-ppe-shell-injection`, `cicd-sec-4-secrets-inherit-pr-target`                                                         | stop checking out the PR head ref in `pull_request_target`                  |
| **Poisoned Exfiltration**                | CRITICAL | `cicd-sec-4-ppe-shell-injection` + a reachable secret (`cicd-sec-6-hardcoded-secrets`, `cicd-sec-2-long-lived-pat`, `cicd-sec-7-debug-logging-enabled`, or `cicd-sec-6-secret-in-run-output`)                                                              | route untrusted input through an env var instead of the shell               |
| **Injected Runner Takeover**             | CRITICAL | `cicd-sec-4-ppe-shell-injection` + `best-prac-3-self-hosted-runners` (same workflow); amplified by `best-prac-2-missing-timeout`                                                                                                                           | route untrusted input through an env var instead of the shell               |
| **Untrusted Code on Self-Hosted Runner** | HIGH     | untrusted fork content (`cicd-sec-1-ppe-checkout` or `cicd-sec-1-workflow-run-artifact-poisoning`) + `best-prac-3-self-hosted-runners`; amplified by `cicd-sec-1-checkout-persist-credentials`, `cicd-sec-5-missing-permissions`, `cicd-sec-4-wperm-write` | stop running untrusted fork content, or use ephemeral GitHub-hosted runners |
| **Secret Exposure in Logs**              | HIGH     | `cicd-sec-7-debug-logging-enabled` + an exposed credential (`cicd-sec-6-hardcoded-secrets` or `cicd-sec-6-secret-in-run-output`)                                                                                                                           | remove the debug-logging env entry                                          |
| **Unverifiable Release**                 | HIGH     | `slsa-build-l2-provenance` + `cicd-sec-3-unpinned-action`; amplified by `slsa-build-l2-verify-step`                                                                                                                                                        | generate a build-provenance attestation for published artifacts             |
| **Persistent Supply-Chain Foothold**     | HIGH     | `cicd-sec-3-unpinned-action` + `best-prac-3-self-hosted-runners`; amplified by `best-prac-2-missing-timeout`                                                                                                                                               | pin the action to a full commit SHA                                         |
| **Untrusted RCE on Infra**               | HIGH     | `best-prac-1-pipe-to-shell` + `best-prac-3-self-hosted-runners`; amplified by `cicd-sec-4-wperm-write`                                                                                                                                                     | download, verify, then execute — never pipe to a shell                      |
| **Silent Supply-Chain Tampering**        | HIGH     | `cicd-sec-9-download-without-checksum` + (`cicd-sec-3-unpinned-action` or `cicd-sec-10-continue-on-error-job`)                                                                                                                                             | verify a checksum/signature for every download                              |
| **Open Trigger Secret Leak**             | HIGH     | `cicd-sec-8-repository-dispatch-unfiltered` + (`cicd-sec-7-debug-logging-enabled`, `cicd-sec-6-hardcoded-secrets`, or `cicd-sec-6-secret-in-run-output`)                                                                                                   | add a `types:` allowlist to the trigger                                     |

### GitLab combinations

The same engine correlates GitLab CI findings. These mirror the GitHub
scenarios for `.gitlab-ci.yml`:

| Combination                      | Severity | Ingredients (rule IDs)                                                                                                                                        | Breaks when you…                                                      |
| -------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| **GitLab Pwn Request**           | CRITICAL | `cicd-sec-1-gl-mr-target` + a reachable secret/injection (`cicd-sec-4-gl-shell-injection`, `cicd-sec-6-gl-hardcoded-secrets`, or `cicd-sec-7-gl-debug-trace`) | don't run jobs that check out MR source code on `merge_request_event` |
| **GitLab Poisoned Exfiltration** | CRITICAL | `cicd-sec-4-gl-shell-injection` + a reachable secret (`cicd-sec-6-gl-hardcoded-secrets`, `cicd-sec-2-gl-pat-secret`, or `cicd-sec-7-gl-debug-trace`)          | route untrusted `$CI_*` input through an intermediate variable        |
| **GitLab Persistent Foothold**   | HIGH     | `cicd-sec-3-gl-unpinned-include` + `best-prac-3-gl-self-hosted-tags`; amplified by `best-prac-2-gl-missing-timeout`                                           | pin every `include:` to an immutable ref                              |

## Where to see them

* **CLI** — every scan prints an *Attacker Mind — Toxic Combinations* section
  after the findings (and includes them under the `toxic_combinations` key in
  [JSON output](/cli/usage#json-output)).
* **Web app** — the [Attacker Mind dashboard](/webapp/attacker-mind) aggregates
  combinations across all your repositories and draws each attack chain.
