Skip to content

AC-04.02: needs a remediation path for excessive-permissions findings (zizmor --fix doesn't cover this audit) #277

@mlieberman85

Description

@mlieberman85

Summary

After #276 landed, OSPS-AC-04.02 (ScopedPermissions) gets accurate detection of over-broad workflow permissions via zizmor's excessive-permissions audit. But there's no remediation path in the same control — when the audit flags a finding, darnit can only tell the user "manually narrow your permissions."

What I confirmed about zizmor --fix

Tested zizmor 1.25.2 against mlieberman85/darnit-gittuf-demo (the feature 014 demo repo):

--fix mode Patched What got fixed
safe 1 file obfuscation (unwrapped ${{ 'ubuntu-latest' }})
all 4 files + artipacked (added persist-credentials: false to checkout invocations)

In both modes, excessive-permissions findings survived. Looking at zizmor's verbose output, only findings tagged note: this finding has an auto-fix get auto-fixed; excessive-permissions doesn't carry that tag. zizmor knows how to detect over-broad permissions but doesn't yet know how to programmatically narrow them — that requires authoritative "action X needs permission Y" tables that zizmor doesn't yet maintain.

So we can't just delegate to zizmor --fix.

Why this matters

enable_branch_protection is darnit's flagship example of "audit catches → tool fixes." OSPS-AC-04.02 is currently audit-only:

For the demo, a Claude Code session ended up reading the workflow source, scoping the actions' real needs, and applying the narrowing by hand — see mlieberman85/darnit-gittuf-demo#2. That worked but is exactly the kind of step darnit could automate.

Proposed approaches (pick one or sequence them)

A. LLM-led remediation handler (recommended near-term)

Add a remediation handler that builds an LLM consultation payload like darnit already does for the threat-model handler:

# Pseudo-shape
{
  "action": "narrow_workflow_permissions",
  "workflow_path": ".github/workflows/ci.yml",
  "current_permissions": "read-all",
  "zizmor_finding": { …},
  "actions_used": [
    {"name": "actions/checkout@…", "step_idx": 0, "with": {…}},
    {"name": "actions/setup-go@…", "step_idx": 1, "with": {…}},
    …
  ],
  "instructions": "For each action, identify its minimum required GitHub
                   permissions. Union the required perms. Replace the
                   workflow- or job-level permissions block with a
                   minimum-needed YAML block. Verify with `zizmor` that
                   the finding closes."
}

The calling agent (Claude Code via MCP) does the reasoning + the file edit. The remediation handler returns a structured prompt; the agent commits + opens a PR.

Pros: cheap to add, matches darnit's existing pattern for SA-01.01 / SA-03.02 / governance docs. Cons: leans on the agent to be correct.

B. Static action → permissions map

Maintain a curated dict of {"action-name@ref": ["contents:read", …]} for common actions. Compute the union per workflow + write the narrowed block deterministically.

Pros: predictable, no LLM dependency. Cons: large curation surface, will rot as actions evolve, doesn't handle custom or proprietary actions.

C. Hybrid

Static map for common actions (covers ~80% of workflows trivially); LLM consultation path for the long tail. Best of both, more code.

D. Track upstream zizmor

Watch for excessive-permissions to graduate into --fix-eligible. If/when it does, AC-04.02 can simply pipeline zizmor --fix=safe as a deterministic remediation step. No bet on timeline.

Suggested acceptance for option A (smallest workable PR)

  • New entry in AC-04.02's [remediation] block with a handler = "llm_remediation" (or similar; same plumbing as threat-model verification prompts).
  • Handler emits the payload above.
  • Darnit's darnit-remediate skill knows how to consume it: read the workflow, propose a minimum-permissions YAML diff, apply on a branch, run zizmor, open PR.

Related

Out of scope (for this issue)

  • Doing the same for other zizmor audits (impostor-commit, unpinned-uses, dangerous-triggers) — those map to other OSPS controls and warrant their own remediation tracks.
  • Building a generalised "any zizmor finding → LLM remediation" pipeline. The current issue is specifically the AC-04.02 gap; broader integration can be considered later.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions