Start With Entry Points
WordPress plugin auditing starts with entry points. I look for AJAX actions, REST API routes, shortcode handlers, admin pages, import and export features, upload handlers, cron jobs, hooks, filters, and any feature that accepts user-controlled input. The goal is to understand how external input enters the plugin and what privilege level is required to reach it.
Many plugin bugs are not in the main admin page. They often live in secondary handlers that were added for convenience: background importers, preview endpoints, export downloads, debug actions, template renderers, or unauthenticated AJAX callbacks. Those paths can bypass the stricter checks used by the visible UI.
Capability Checks Are The Boundary
In WordPress, authentication alone is rarely enough. The important boundary is capability. A logged-in subscriber, contributor, author, shop manager, and administrator should not have the same access. I check whether each sensitive action uses the correct capability and whether object-level ownership is enforced when needed.
A common pattern is a route that checks only whether a user is logged in, then accepts an object identifier and performs an action on that object. That becomes dangerous when the object belongs to another user, represents a privileged setting, or triggers server-side behavior. Capability checks should be close to the sensitive operation, not only near the UI.
Nonce Checks Are Not Authorization
Nonces help protect actions from cross-site request forgery, but they do not replace authorization. A valid nonce means the request likely came from a page rendered to the user. It does not mean the user should be allowed to perform the action.
When reviewing a route, I treat nonce validation and capability validation as separate questions. Does the nonce prevent unwanted cross-origin action? Does the capability check prevent a low-privilege user from performing the action intentionally? Both are needed for sensitive state changes.
Storage And Delayed Execution
A lot of WordPress impact appears after data is stored. A low-privilege user may save a setting, template, widget, profile field, form value, or imported record that later renders in an administrator context. That creates delayed sinks for stored XSS, template injection, unsafe redirects, file operations, and SSRF-like behavior.
I follow stored values through the plugin lifecycle. Where is the value saved? Is it sanitized before storage or escaped at output? Is it later used in SQL, HTML, JavaScript, file paths, HTTP requests, or command-like behavior? The same value can be safe in one context and unsafe in another.
File And Path Handling
Import, export, backup, restore, media, template, and cache features deserve extra attention. I look for path traversal, arbitrary file read, arbitrary file write, extension bypass, archive extraction issues, unsafe temporary files, and predictable file names.
The dangerous cases usually combine weak normalization with trust in user-controlled names. A plugin may block '../' but forget encoded variants, Windows separators, archive entry names, symlinks, or paths passed through multiple decode steps. A strong review checks the final resolved path, not just the raw input string.