WP Abilities Permission Auditor
PHP · WP-CLI · SECURITY AUDIT
As the WordPress Abilities API opens capabilities to automation, MCP and AI clients, a capability that was merely generous becomes an exposed surface. This auditor finds least-privilege violations and maps them to Abilities-style descriptors for review.
- Maintainer
- Pixy Puala
- Vertical
- Security · Least privilege
- Year
- 2026
- Role
- Open source
- Stack
- PHP
- Status
- ● Public repo
- Verified
- Source on GitHub
Problem
Role and capability grants accumulate quietly — a plugin adds one, a client asks for another, and nobody re-reads the matrix. When those capabilities become machine-callable, an over-granted editor role turns into a code-execution or account-control path. The gap is that nobody was looking.
Constraints
Decisions
Non-zero exit on findings
The CLI is designed to be a CI gate. A finding fails the build; a clean run is a recorded artefact. A pretty admin table alone changes nothing.
Deterministic JSON export
Output is stable and diffable, so a capability change shows up in review as a diff instead of requiring someone to re-read a matrix by eye.
Read-only by design
The tool reports; it never edits roles. An auditor that mutates the thing it audits is a new class of incident.
Build
Stack
- ▸ PHP · Composer
- ▸ WP-CLI command · admin screen
- ▸ Risk policy engine · capability → risk mapping
- ▸ Deterministic JSON export
- ▸ PHPUnit · PHPCS/WPCS clean
- ▸ GitHub Actions · PHP 8.1 and 8.3
Tooling
- ✓ kept Composer · WP-CLI · GitHub Actions
Results · Measured
Verified against a live WordPress 7.0.2 + WooCommerce install, where it surfaced a genuine finding — WordPress grants unfiltered_html to the editor role — in both text and JSON output, recorded in docs/RUNTIME-VERIFICATION.md.
Tradeoffs
Broader Abilities API coverage waits for that API to stabilise; chasing a moving spec would ship churn. The admin screen is registered but has not been driven through a browser test, so the CLI is the surface with proof behind it.