
How to security-audit a WordPress plugin
Find the real vulnerabilities — before an attacker does.
A step-by-step guide to reviewing a plugin’s source for exploitable security flaws — by hand, or automatically with an AI agent in a local playground.
To security-audit a WordPress plugin: put a copy of the site in a local playground (never audit against production), map every place the plugin accepts untrusted input, grep its source for dangerous sinks — raw SQL, unescaped output, unguarded AJAX and REST handlers, file and shell operations — then trace each candidate from input to sink and report only the ones with a real, exploitable path. Pete Panel’s /plugin_audit workflow runs this whole review automatically, read-only, and hands you a severity-ranked report.
Why plugins are where WordPress gets hacked
Year after year, the overwhelming majority of WordPress compromises trace back not to core but to plugins — a single missing capability check or an unprepared SQL query in one file of one plugin is enough. Every plugin you install runs with the full power of your site: it can read the database, write files, and create users. Yet most sites run dozens of plugins nobody has ever read. A security audit is simply reading that code the way an attacker would — following what happens to a request parameter after it enters the plugin — and it’s methodical enough that you can do it step by step. Here’s the process.
The steps, start to finish
Audit a copy in a local playground — read-only
Clone the site (or just the plugin) into a local dev playground. A source audit only needs the files, so it should never touch production, never run the plugin’s code, and never modify anything. Static review means the workflow can’t break a live site by design.
Scope the plugin
List its PHP files, note the version from the main file’s header, and identify third-party vendor/ code (check it against known CVEs, but focus deep review on the plugin’s own code). If you skip or sample anything, say so in the report — silent gaps read as “clean.”
Grep for the dangerous sinks
Search the source for the operations attackers reach for: $wpdb queries built with string interpolation, echo of request data, include/file_get_contents with dynamic paths, unserialize, exec-family calls, and REST routes with permission_callback => '__return_true'. Every hit is a candidate — not yet a finding.
Trace each candidate from source to sink
A finding is real only when untrusted input — $_GET, $_POST, cookies, REST or AJAX params — actually reaches the sink. Ask: can an unauthenticated or low-privilege user reach this entry point? wp_ajax_nopriv_* handlers deserve the hardest look, because anyone on the internet can call them.
Check the guards WordPress expects
For each traced path, verify the right protection for that sink: $wpdb->prepare() for SQL, esc_html/esc_attr/wp_kses for output, and — on anything that changes state — both a nonce check and current_user_can(). A write reachable without nonce and capability is a finding on its own, even with clean input.
Adversarially verify — kill the false positives
Before reporting anything, try to refute it: is the “untrusted” value actually hardcoded upstream? Does a shared admin_init capability check already cover the handler? Flagging correctly-guarded code destroys trust in the whole report — only keep findings you can state a concrete exploit path for.
Rank honestly by severity
Critical means unauthenticated remote code execution, SQL injection, or auth bypass. CSRF on meaningful state lands at medium; defense-in-depth nits are informational. Don’t inflate severity to look thorough — an honest short report beats an alarming long one.
Report with data flow and a specific fix
For each finding: the vulnerable lines, the input-to-sink data flow, a concrete exploit scenario in prose, and the WordPress-correct fix. Close with an overall risk verdict and a one-line “what to fix first,” so the report drives action instead of anxiety.
How to run it: /plugin_audit, step by step
Every step above — scope, grep, trace, verify, rank, report — is exactly what Pete Panel’s /plugin_audit workflow does for you. Inside a local agentic WordPress environment, an AI agent reads the plugin’s source, follows each untrusted input to its sink, challenges its own findings to kill false positives, and writes a severity-ranked report. It is read-only and local-only by design: it never modifies the plugin, never touches the database, and never connects to production. Here’s the whole run, start to finish.
1. Pick a plugin and find its path
The workflow takes one argument: the plugin’s directory inside your playground. Every plugin lives under wp-content/plugins/ in your site folder, so the path always follows the same shape:
/var/www/html/<your-site-folder>/wp-content/plugins/<plugin-name>
Not sure of the exact folder name? Ask the agent to list them — wp plugin list prints every installed plugin’s slug, which is the last part of the path.
2. Run the workflow
In your playground’s agent session, run /plugin_audit with that path. One command kicks off the entire review:
/plugin_audit /var/www/html/deploypete/wp-content/plugins/your-plugin
The agent scopes the plugin (and tells you if it splits a large one across sub-reviews rather than silently skipping files), greps for the dangerous sinks, then traces each candidate from input to sink and verifies the guards WordPress expects. You don’t drive any of it — you read what comes back.
3. Read the report
You get a severity-ranked markdown report — summarized in the chat and saved to a file you can keep or share:
~/Sites/plugin_audits/<plugin-name>-<timestamp>.md
Every finding carries the same anatomy, so it drives action instead of anxiety: a severity (Critical down to Info), the exact file:line and vulnerable lines, the input-to-sink data flow, a concrete exploit scenario in plain prose, and the WordPress-correct fix. The report closes with an overall risk verdict and a one-line “what to fix first.” Fixes are a separate, deliberate step — the audit hands you the map, you decide what to patch.
Frequently asked questions
Can an AI agent really audit a WordPress plugin?
Yes — a source audit is reading and reasoning about code, which is exactly what an agent with file access does well. The /plugin_audit workflow follows the same discipline a human reviewer would: enumerate sinks, trace input to sink, verify guards, and challenge every finding before reporting it. You review the report; the grind of reading every handler is the part that’s automated.
Will the audit modify my site or the plugin?
No. The audit is static and read-only: it reads the plugin’s source files and writes a report. It never edits the plugin, never executes its code, never queries the live database, and never connects to production. The deliverable is a findings report — fixes are a separate, deliberate step after you’ve read it.
What kinds of vulnerabilities does it find?
The classes that actually get WordPress sites hacked: SQL injection, reflected and stored XSS, CSRF and missing capability checks on state-changing actions, unauthenticated AJAX and REST handlers, file inclusion and path traversal, SSRF, PHP object injection, and hardcoded secrets. Each finding comes with the data flow and a concrete exploit scenario, not just a pattern match.
Isn’t every grep hit a vulnerability?
No — and that’s the difference between a useful audit and noise. A raw $wpdb->query() is only a finding if attacker-controlled input reaches it without $wpdb->prepare(). The verify step exists to kill false positives: values that are hardcoded upstream, handlers already covered by a shared capability check, output that’s correctly escaped. Only traced, exploitable paths make the report.
Should I audit plugins on my production server?
No. Audit a copy in a local dev playground. Static review only needs the files, and keeping the audit local means it structurally cannot touch a live site. If a plugin only exists on production, pull it into a playground first — that’s a deliberate copy step, not an SSH session into your live server.
Know what your plugins are really doing.
Spin up a free dev playground, clone your site, and run /plugin_audit — a severity-ranked security report, read-only, production never in the loop.
