Least Privilege Auditor
SkillDev toolsVerify the receipt ids behind a normalized authority-usage summary, compare that evidence with granted scopes, and propose the narrowest grant the evidence supports.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Least Privilege Auditor skill
What this skill tells your AI
The instructions your AI receives, as published by runxhq/runx in skills/least-privilege/SKILL.md and read by ahel’s review.
Turn granted authority plus attributable observed usage into a bounded attenuation proposal.
This skill resolves every supporting receipt id through the native ledger
runner before comparing exercised scopes from Runx's redacted receipt detail
with the current grant. Native detail is authoritative for scope use. A supplied
usage summary exists only for deterministic replay of older evidence that lacks
that projection. Missing receipt proof defers every scope. The output is a
reviewable attenuation proposal, not an automatic change.
Composes
ledger#read
What this skill does
- Diff granted authority against receipt-backed usage.
- Classify each granted scope as
keep,narrow,remove, ordefer. - Propose the narrowest grant that still covers observed usage.
- State residual risk after attenuation.
- Emit a receipt-quality report a reviewer can apply or reject.
When to use this skill
- Periodic least-privilege review of a skill, grant, or principal before publish, renewal, or maturity promotion.
- After an incident, to identify authority that can be safely removed without breaking observed behavior.
- Before expanding distribution of a public skill, to prove its grant is minimal against real receipts.
- When a reviewer asks for a scope-by-scope evidence trail, not just a summary.
When not to use this skill
- To grant new authority. This skill only narrows; widening is a human decision.
- When no usable receipt evidence exists. Return
needs_more_evidencerather than guessing a grant down to nothing. - For secret material handling or credential exposure. Use the appropriate secret-leak triage flow instead of scope review.
- When the user asks for automatic permission changes. Produce a proposal and stop unless a separate approved delivery lane exists.
- When grant semantics are unknown and cannot be normalized. Return
needs_inputwith the exact syntax or policy question.
Procedure
-
Scope the audit target.
- Identify
subject, grant source, receipt ids or receipt window, and whether receipts are from the same principal or skill version. - Gate: if the subject, grant list, or usage source is ambiguous, stop with
needs_input. - Evidence expected: subject id or label, granted scope list, receipt ids or an explicit statement that no receipts were available.
- Identify
-
Normalize granted scopes.
- Parse each scope into verb, resource, path or namespace, conditions, and wildcard breadth.
- Preserve original scope strings. Do not rewrite policy syntax casually.
- Gate: if a scope cannot be parsed, keep it as
deferand request the missing policy semantics instead of treating it as unused.
-
Build the usage model from attributable evidence.
- Resolve each supporting receipt id through
ledger read. - Read exercised scopes and receipt references from native redacted receipt detail. Use the supplied usage summary only when replaying older evidence.
- Count successful use separately from denied or dry-run checks.
- Do not infer scope usage from a successful high-level task alone; cite the receipt step or policy check that exercised the authority.
- Resolve each supporting receipt id through
-
Classify every granted scope.
keep: at least one observed successful use requires the granted scope as written, or a reserved/break-glass policy explicitly requires it.narrow: all observed uses fit a strictly smaller verb, resource, namespace, condition, or path.remove: no observed use, denied check, or documented reserved purpose supports the scope.defer: evidence is conflicting, receipt attribution is weak, or policy semantics are unknown.
-
Propose attenuation.
- Remove scopes classified as
remove. - Downgrade scopes classified as
narrowonly when every observed use fits the narrower grant. - Leave
keepanddeferscopes unchanged in the proposed grant. - Gate: never produce a proposal narrower than the evidence supports. A scope used once is used.
- Remove scopes classified as
-
State residual risk and reviewer action.
- Name what the proposed grant can still do.
- Name any broad scope kept despite thin evidence and why.
- Separate
applyable nowfromneeds human policy decision.
-
Emit receipt expectations.
- A valid receipt for this skill should record input grant count, receipt sources, classification counts, proposed removals or narrowings, stop status, and unresolved questions.
Edge cases and stop conditions
- Empty or unattributable usage evidence: return
needs_more_evidence; do not remove all scopes by default. - Missing granted scopes: return
needs_input; there is no baseline to diff. - Receipt subject mismatch: return
needs_inputwith the mismatched subject or version. - Conflicting receipts: classify affected scopes as
deferand returnneeds_humanif the conflict changes the proposal. - Wildcard grants: narrow only to observed resource prefixes when receipt coverage is representative; otherwise keep and flag residual risk.
- Reserved, compliance, or break-glass scopes: keep unless the operator provides explicit policy authority to remove them.
- Dry-run-only use: do not count as successful exercised authority unless the grant exists solely for validation.
- Grant already matches usage: return
no_changewith the evidence summary. - User asks to hide or omit unused authority: refuse that part and report the complete scope diff.
Output schema
Return a structured report with these fields:
status: attenuation_proposed | no_change | needs_more_evidence
subject: string
evidence:
receipt_ids: [string]
receipt_window: string | null
grant_source: string | null
limitations: [string]
scope_diff:
- granted_scope: string
normalized:
verb: string | null
resource: string | null
conditions: object | null
observed_use:
count: number
verbs: [string]
resources: [string]
receipt_refs: [string]
classification: keep | narrow | remove | defer
proposal: string | null
rationale: string
attenuated_grant: [string]
removed_scopes: [string]
narrowed_scopes:
- from: string
to: string
kept_scopes: [string]
deferred_scopes: [string]
residual_risk: [string]
reviewer_action: applyable_now | gather_more_receipts | none
receipt_expectations:
classification_counts: object
stop_status: string
unresolved_questions: [string]
Worked example
Input:
subject: skills/report-exporter
granted_scopes:
- drive.files.read:/reports/*
- drive.files.write:/reports/*
- drive.files.delete:/reports/*
receipt_ids: [rx_101, rx_102]
usage_summary:
observed:
- scope: drive.files.read:/reports/*
count: 8
refs: [rx_101:step_3, rx_102:step_2]
- scope: drive.files.write:/reports/*
count: 2
refs: [rx_101:step_6, rx_102:step_5]
Output:
status: attenuation_proposed
subject: skills/report-exporter
removed_scopes:
- drive.files.delete:/reports/*
narrowed_scopes: []
kept_scopes:
- drive.files.read:/reports/*
- drive.files.write:/reports/*
attenuated_grant:
- drive.files.read:/reports/*
- drive.files.write:/reports/*
residual_risk:
- The skill can still read and write any file under /reports/*.
reviewer_action: applyable_now
The delete scope is removable because no cited receipt exercised delete authority. The read and write scopes stay because each was used at least once.
Inputs
subject(optional): skill id, grant id, principal, or other label for what is being audited.granted_scopes(required): the current scopes granted to the subject, preferably in canonical policy syntax.receipt_ids(required): exact receipt ids supporting the audit.usage_summary(optional): legacy replay supplement with anobservedarray of scope, count, and receipt refs; live runs use native receipt detail.receipt_rows(optional): native-projection rows for deterministic replay; live runs resolvereceipt_idsfrom the configured receipt store.receipt_details(optional): native redacted detail projections for deterministic replay; live runs resolve them fromreceipt_ids.objective(optional): operator intent that focuses the review, such as "prepare for public publish" or "post-incident attenuation".policy_notes(optional): reserved scopes, compliance constraints, or human-approved exceptions that affect removal decisions.
Signals
- GitHub stars
- 87
- Forks
- 101
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
least-privilege- Source
- github.com/runxhq/runx