Skip to main content
The app.pipefort.com/attacker-mind page surfaces toxic combinations — sets of findings that together enable a higher-impact compromise — across every connected repository’s latest scan.

Four views of the same chains

The screen asks one question four ways. The view switch in the toolbar picks which:
  • by scenario (default) — one row per chain, worst first, with the ingredients that produced it, where it lives, and the change that breaks it.
  • by repository — the same chains grouped under the repository they were found in, each drawn as its stages so the walk is legible. For when you own a repository rather than a category of risk.
  • by fix — the chains grouped by the change that clears them, ranked by how many each one collapses. One fix that breaks three chains outranks three fixes that break one each.
  • as a graph — each chain drawn stage by stage, in the order the compromise runs. The other three cuts compress a chain to a line of arrows, which is enough to recognise one you already know; this one is for the chain you don’t. Same chains, same criticality filter — only the drawing differs.

How old a combination is

Every chain carries a first seen age beside its ingredients. A combination is not stored the way a finding is — it is correlated fresh on every read — so it has no birthday of its own. The age shown is that of its newest ingredient, because the chain does not exist until the last piece arrives. That distinction matters when you are deciding what to look at first. A repository can carry a pull_request_target checkout for a year in perfect safety; the day someone makes the token writable is the day the Pwn Request exists, and that is the date the screen reports. If any ingredient has no recorded first sighting, no age is shown at all — a chain half of whose components have been sitting there since March should not claim to be two days old. A criticality filter (all / critical / high) narrows every view; the stat band above stays at organization-wide totals, and the count on the right of the toolbar tells you how much the filter is hiding.

Stat band

Combinations, Critical, High, Repos affected, and Fixes that clear them — the distinct changes that would take the chain count to zero. That last number is the one worth reporting weekly. Unlike the open-finding count, which will never be zero, “four changes clear every chain” is a goal a team can actually reach.

Opening the fixes

In the by fix view, a group whose break-the-chain rule has an automated fixer gets a button that opens the pull requests. Because a single fix can span several repositories, the button says how many PRs it will open before you click it, and reports per-repository failures rather than claiming success. Groups with no automated fixer are labelled manual change and have no button — there is nothing that could honestly do the work for you.

On a single repository

The same combinations appear on each repository’s detail page (/repositories/:id), scoped to that repo’s latest scan, in two places:
  • the Toxic combinations rail beside the findings list names each chain, its ingredients and where it lives — enough to know one exists; and
  • the chains tab draws them, the same stage-by-stage graph the org-wide as a graph view uses, with the break-the-chain fix under each one.
Both read the same response, so the tab costs no extra request. When a repo’s findings don’t chain into a higher-impact compromise, the tab says so — and it says it as no combination formed from this repository’s findings, not as a clean bill of health, because the individual findings still stand. Underneath, the same coverage note as the org page states how many shipped combinations were correlated here and matched nothing, so an empty result is a result rather than a gap.

How the data is computed

The page calls GET /api/attack-paths, which loads each repository’s latest-scan findings server-side and runs the same detection engine as the CLI; the dashboard only groups results by repository and rolls up the counts. Because combinations derive from already-persisted findings, the page reflects your most recent scans. Run a scan from the Dashboard or Repositories view to refresh them. A combination never includes a finding from a rule you’ve turned off in Rule settings — which is exactly why the response also carries the catalog of every shipped combination and whether each one could still fire. See What else was looked for.

What else was looked for

Under the detections, the page names the shipped combinations that produced nothing. This is the denominator: a detection list on its own cannot tell you whether thirteen scenarios were evaluated and none matched, or none were evaluated at all — both render as an empty page. Three sentences can appear, and they mean different things:
Muting a rule can silently retire a whole attack scenario. Detection runs over findings that have already passed your rule policy, so turning off one ingredient removes its combinations from the results — and, before this section existed, that was indistinguishable from a clean repository. If a combination matters to you, check it is not in the “not looked for” list before reading the page as good news.
Whether a rule blinds a combination depends on how the chain is built. Several chains accept alternatives — Pwn Request will form from either a missing permissions block or a repository-wide writable token — so disabling one of those costs nothing, and the page does not name it. Only rules that actually left a requirement with no way to be satisfied are listed. Rule policy is per repository, so the same combination can be genuinely quiet in one repository and invisible in the next; the counts behind these sentences are per-repository, not per-organization.

When nothing chains

If none of your repositories’ findings combine into something an attacker could walk end to end, the page says so plainly. Zero is a real result here, not an absence of data — provided the coverage section above confirms the chains were actually searched for.
On an organization with no finished scans the page does not report a clear result at all — it says nothing has been scanned yet and links you to Repositories, and there is no coverage section. “We have not looked” is not a search result, and printing one would dress up an absence of data as a clean bill of health.