Skip to content

Trust model

This page expands the trust model briefly described in SECURITY.md. Read both.

What this wrapper guarantees

  1. Hash-pinned upstream fetch. linpeas-pin.json records an SRI hash for the upstream linpeas.sh asset. Nix refuses to build on hash mismatch — a swapped or corrupted upstream asset fails the build.
  2. Pin-shape validation at flake eval. flake.nix asserts that pin.version matches [0-9]{8}-[0-9a-f]{7,40} and that pin.url starts with https://github.com/peass-ng/PEASS-ng/releases/download/. An attacker-controlled pin file cannot smuggle arbitrary URLs into the derivation.
  3. GitHub Releases API digest cross-check. scripts/bump-linpeas.sh reads the upstream release-asset .digest field over the API and refuses to bump if it is missing, non-sha256:, or does not match the downloaded file. This is not silent on missing data — bump aborts.
  4. Asset URL prefix validation. Same script refuses to record any asset URL outside the expected peass-ng/PEASS-ng/releases/download/ prefix.
  5. Daily upstream parity check. verify-latest-release.yml re-fetches the pinned linpeas.sh daily and re-checks the SRI hash. Detects upstream tag replacement (intentional or compromised).
  6. SLSA build-provenance + SBOM attestations. Each release attaches build-provenance attestations binding the pin file, the bundle, and the per-arch OCI images to the release-on-bump.yml workflow run, plus SPDX-JSON SBOMs (bundle + per-arch images) generated by anchore/sbom-action and attested via actions/attest-sbom. Verifiable with gh attestation verify — see Verification.

What this wrapper does not guarantee

  • Content trust on upstream linpeas.sh. Upstream PEASS-ng ships no GPG, cosign, or SLSA signatures. The SRI hash binds you to some upstream asset, but it cannot prove that upstream's release is benign. If upstream is compromised, this wrapper will faithfully ship the compromise.
  • Reproducibility of upstream. The wrapper is reproducible. The wrapped script is whatever upstream chose to publish.
  • Site-level signing. The Pages site you are reading is documentation, not a verifiable artifact. Do not treat dashboard text as a substitute for gh attestation verify.

Auto-merge surface

Three automations may auto-merge PRs into main when CI passes:

  1. update-linpeas.yml — daily 09:00 UTC pin bumps. Opens a PR authored by github-actions[bot], gated by all required CI checks, auto-merged on green.
  2. update-flake-lock.yml — weekly nixpkgs input bump. Split into a contents: read compute-lock job (runs nix flake update) and a push-and-merge job that mints a linpeas-flake-bumper GitHub App installation token and uses only GitHub-owned action SHAs. The third-party DeterminateSystems/update-flake-lock action was removed so the bump credential never enters a third-party action's env. Same CI gating.
  3. Renovate — Friday batch for GitHub Action SHA pins, the pinned Nix installer version, and tracked flake inputs (nixpkgs stable branch, cachix/git-hooks.nix). All PRs honor a non-empty minimumReleaseAge (7 days) and per-manager automerge scopes; the renovate-invariants CI lint enforces both. Same gating.

A compromise of the linpeas-flake-bumper GitHub App installation token used by update-linpeas.yml would let an attacker open a PR with arbitrary changes. The App is installed only on this repository with Contents: Read and write + Pull requests: Read and write permissions; the installation token is minted per job, lives one hour, and revokes at job end. The auto-merge bot would still gate on CI — so any malicious change would have to also pass all required checks (build, smoke, attestation re-verify, SRI cross-check). See docs/security/repo-config.md for the full credential model.

See SECURITY.md for the secret rotation policy.

Currently pinned

Field Value
Pin version 20260510-cd4bd619
Pin URL https://github.com/peass-ng/PEASS-ng/releases/download/20260510-cd4bd619/linpeas.sh
Upstream latest 20260510-cd4bd619
Drift 0 days
Last parity check success (2026-05-19T13:07:58Z)

Bump credentials blast-radius

  • Bump workflows authenticate as the linpeas-flake-bumper GitHub App, not as a PAT. The App is installed only on rvenutolo/linPEAS-flake with Contents: Read and write + Pull requests: Read and write permissions (Metadata: Read is implicit). No Workflows permission. Switching back to any PAT-based flow is a regression — web-flow signing of REST PUT /contents requires an App installation token, empirically confirmed (plan 04).
  • Storage:
  • vars.BUMP_APP_CLIENT_ID — public, GitHub App Client ID (e.g. Iv23...). Preferred over App ID (numeric) per the actions/create-github-app-token v3 deprecation.
  • secrets.BUMP_APP_PRIVATE_KEY — App's PEM private key. Rotate on suspected compromise; no forced cadence.
  • Tokens minted via actions/create-github-app-token are scoped to one job, valid one hour, and revoked at job end. They live only as ${{ steps.app-token.outputs.token }} passed via GH_TOKEN. Never reach .git/config; there must never be a git push using them. Commits land via REST PUT /repos/{owner}/{repo}/contents/{path} → web-flow-signed by GitHub.
  • BUMP_APP_PRIVATE_KEY only enters env in push-and-merge jobs, never compute-pin / compute-lock. Those compute jobs must remain permissions: contents: read, must not reference the secret, and must keep untrusted Nix actions inside their own boundary.
  • docs/security/required-checks.md mirrors the protect-main branch ruleset's required-check set. Update in same change as GitHub-side list changes.
  • No paths: / paths-ignore: filter on any workflow listed in docs/security/required-checks.md. Enforced by required-checks-no-paths CI job.

PR-triggered workflow secret allowlist

PR-triggered workflows (on: pull_request or on: pull_request_target) MUST NOT reference any secrets.* other than secrets.GITHUB_TOKEN. Enforced by scripts/check-pr-workflows-no-secrets.sh via pr-workflows-no-secrets required CI job.

Exception for a non-GITHUB_TOKEN secret requires documenting here BEFORE relaxing the script.

harden-runner

step-security/harden-runner is the first step in every job in every workflow. egress-policy: audit.

  • Do not remove from any job.
  • Keep as first step, before actions/checkout, cachix/install-nix-action, or any network step. eBPF monitor must install before any I/O.
  • Do not add to composite actions — caller job already has it.