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

# SLSA-BUILD-L2 — Permissions block grants overly broad scopes

> An explicit permissions block that grants write-all defeats least privilege.

| Field      | Value                                                          |
| ---------- | -------------------------------------------------------------- |
| Rule ID    | `slsa-build-l2-perms-overly-broad`                             |
| Severity   | **HIGH**                                                       |
| SLSA level | [v1.2 Build L2](https://slsa.dev/spec/v1.2/build-track-basics) |
| Auto-fix   | partial ([what it does](#auto-fix))                            |

## What the check does

Fires when a workflow- or job-level `permissions:` block either:

* Sets the scalar `permissions: write-all`, **or**
* Declares four or more scopes all set to `write` (an exhaustive write map).

## Why it matters

SLSA Build L2 hardening expects **least privilege** — only the scopes the
workflow actually needs should be writable. `write-all` is strictly worse
than the implicit default: it gives reviewers the impression that
permissions have been considered when they haven't been.

This rule is the sibling of [`cicd-sec-5-missing-permissions`](/rules/cicd-sec-5):
one fires on *absence* of a block, this one fires on *excess*.

## Vulnerable example

```yaml theme={null}
name: ci
on: push
permissions: write-all              # ← antipattern
jobs:
  build:
    runs-on: ubuntu-latest
    steps: [{ run: ./build.sh }]
```

## Safe example

```yaml theme={null}
name: ci
on: push
permissions:
  contents: read
jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write              # ← only this job actually needs it
    steps: [{ run: ./publish.sh }]
```

## Auto-fix

`--fix` handles the scalar form: `permissions: write-all` (workflow- or job-level) is rewritten to `permissions: read-all`. That's the safe default — every step can still read code and metadata, no writes.

The **mapping form** (4+ scopes all set to `write`) is left for manual review. We can't tell from YAML alone which of those scopes the workflow actually needs, and silently dropping them would break the build. Start from `contents: read` and add scopes per-job as needed.
