Some stats on #php2shell. In the 10 hours before it was publicly announced, across the @Cloudflare network we saw thousands of attempts to exploit it. That jumped to tens of thousands in the 45 minutes post announcement, hundreds of thousands within 2 hours, and millions now.
More Vulnerabilities, Faster Attacks: Lock Down WordPress Behind Cloudflare
This week's PHP flaws are why we now recommend putting as much of a managed WordPress site behind Cloudflare as possible. It applies to traditional WordPress sites and headless ones alike; here is how we do it.
On October 21, PHP shipped emergency releases for two flaws in PHP itself, the programming language WordPress is written in. Because the bug sits below WordPress, no plugin or core update could help. Most of our WordPress clients use a managed host so they don't have to think about servers and patches. That's still the right call, and Kinsta, Cloudways and WP Engine, the hosts our clients use, all patched promptly.
While this vulnerability itself hasn't had widespread exploitation, it had a lot of awareness across IT and marketing teams that don't normally pay attention to security issues. Our hope is that this will be a wake-up call that the status quo on security won't fly in the new world of ever-increasing AI attacks and vulnerabilities.
The growing threat
PHP got the attention, but the problem is much broader. In the past 10 days alone: a Brotli flaw that started as a Node.js bug and triggered emergency patches well beyond it, an out-of-band Next.js patch for two bugs, three Ruby regex engine fixes, and a GitLab flaw rated CVSS 10, the top of the industry's 0 to 10 severity scale.
The number of new vulnerabilities is climbing fast. Each publicly known security flaw gets an ID called a CVE (short for Common Vulnerabilities and Exposures), so counting CVEs is a rough way to count flaws. By the count in CVE Tracker, which tallies the public CVE list, 86,554 CVEs were published in 2026 through October 26, against 48,151 in all of 2025. September alone had 14,934, more than three times September 2025.
Even if you were to dedicate resources and apply every patch as it's available, attackers are finding things before the patches are out.
Cloudflare had rules in its WAF, the web application firewall that screens requests before they reach your site, before most of us had read the advisory. Its write-up says protection went live at 3:02 am UTC on October 21, about nine hours before public disclosure, on every plan with the WAF turned on, including Free.
They needed the head start:
Outsource to Cloudflare
Putting as much of the site as possible behind Cloudflare and closing every way around it is the best (and mostly free) way of protecting your site. They have the infrastructure to see and detect attacks and give you a protective moat, but only if you secure everything behind it.
This applies whether your WordPress site is traditional, where WordPress builds the pages visitors see, or headless, where WordPress only stores the content and a separate site such as Next.js shows it. Many of our clients run traditional WordPress, and almost every step below applies to them as is. Our example uses our headless setup, and we note where the two differ.
Editors sign in through Cloudflare Access
Cloudflare Access is a sign-in gate. We put it in front of the WordPress login and admin area (/wp-login.php and /wp-admin), on traditional and headless sites alike, so editors sign in with the Google or Microsoft account they already use, two-factor included, before WordPress shows them anything. Bots trying stolen passwords never reach the login form. A small plugin then double-checks that sign-in on the WordPress side, so a request that slipped past Access is still turned away.
Lock down the APIs
An API is a door other software uses to read or change your site's content. WordPress has several, and each one needs a decision. A headless site depends on them; a traditional site often doesn't use them at all, which makes closing them even easier:
GraphQL, which a headless Next.js site uses, goes behind Access with a service token: a credential only your site holds. Everyone else gets a sign-in page instead of your content.
WPGraphQL Smart Cache can go further. Its "allow only specific queries" mode answers just the queries your site has saved and returns "Query Not Found" to everything else, and those saved queries cache well.
The REST API is on by default, on traditional sites too. If nothing public needs it, it goes behind Access as well. Check first that no form calls it from a visitor's browser.
XML-RPC is an older API that lets bots try many passwords at once. We block it, unless the site relies on Jetpack or the WordPress mobile app.
Close the back door to the server
Every server has a public IP address, and old DNS records and certificate logs make it easy to find. A request sent straight to that address never touches Cloudflare. The goal is simple: only Cloudflare's addresses can reach the web server, only specific IPs can connect over SSH (the remote login developers use to manage a server), and everything else goes through Cloudflare.
If WordPress runs on a server you control, like a DigitalOcean droplet or a Linode, use a Cloudflare Tunnel. The server connects out to Cloudflare, so there's no public port to go around.
On a managed host it depends on the host. Kinsta runs every site behind Cloudflare and lets you limit SSH and SFTP to an IP allowlist. Cloudways has a Disable Application Access via IP setting, but it only checks which site a request asks for, not where it came from: on our client's server, a request sent to the IP that named the site went straight through. The real fix there is a support ticket, and Cloudways confirmed they can do it:
Please restrict [domain] (app: [app name]) so only Cloudflare can reach it:
1. Nginx allowlist for ports 80/443: Cloudflare's IPv4 ranges (https://www.cloudflare.com/ips-v4), 127.0.0.1 and the server's own IP; deny everything else.
2. Match on the connecting IP ($remote_addr), not X-Forwarded-For or CF-Connecting-IP.
3. Confirm SSH/SFTP, backups, monitoring and WP-Cron keep working.Once it's live, a request sent straight to the server's IP should be refused. While you're there, swap the server's certificate for a free Cloudflare Origin Certificate with SSL set to Full (strict).
The front end, too
This section is for headless sites. On a traditional site, WordPress is the front end, so the steps above already cover it.
Most of our Next.js sites run on Vercel, which also shipped php2shell firewall rules before disclosure. Vercel offers many of the same protections, but worth considering is having your whole stack in one place, including all logs for AI agents to sift through.
Vinext 1.0, released September 28, rebuilds Next.js on Vite so the same app can run on Cloudflare Workers. That puts the site, the firewall, Access, and the lock on WordPress in one place, with one set of rules. It's new, and Cloudflare notes some caching features aren't fully supported yet, so test before you move a production site.
What this doesn't replace
It's worth emphasizing that all this doesn't obviate your need to patch PHP, Next.js, etc. Firewall rules buy time, but they can be bypassed, and PHP disclosed another related issue on October 23 that its advisory says needs a settings change until the next release. This week's checklist:
Confirm your host is on PHP 8.5.12, 8.4.27, 8.3.36, or 8.2.35.
Make sure Cloudflare's managed firewall rules are set to block, not just log.
Close the back door, so next time the protection is actually in the path.
PHP will get patched and this week will be forgotten. The gap it exposed won't close by itself.
Use AI on defense, too
Attackers are using AI to find bugs faster, so we use it on the defending side as well. These are the tools we're running with clients:
TruffleHog finds leaked credentials in code repositories, storage buckets and Docker images, then checks whether each one still works, so you know which to rotate first.
CVEngine maps what your organization exposes to the internet (domains, hosts, ports, services), matches it against known exploited CVEs, and confirms which exposures are real. It's open source and runs on your own server.
deepsec, from Vercel, has coding agents review a whole codebase for vulnerabilities and re-checks each finding before it reaches you. It runs on your own infrastructure.
Cloudflare's security audit skill turns a coding agent into a security auditor that works through a multi-phase audit and returns verified findings.
Agents that watch your logs. With the site, firewall and sign-in logs in one place, an agent can read them on a schedule and flag what looks wrong, instead of waiting for someone to notice.
Treat what these tools find as leads for a person to check, not verdicts. Vercel says to treat deepsec like an agent with full shell access, so run it somewhere isolated.
Shrink the target
AI is making attacks cheaper as it makes them more capable. So think about how to shrink what attackers can reach, and how to limit the damage if they do get in. A few places to start:
Trim user accounts. Remove people who've left, and give everyone else only the role they need. An Editor account can't install plugins; an Administrator can.
Cut plugins. Every plugin is someone else's code running on your server. Remove what you don't use, and question what you barely use.
Don't keep data you don't need. Form plugins like Gravity Forms store every submission in WordPress. If those entries already go to your CRM, delete them from WordPress after they sync.
Limit what integrations can do. Use the narrowest key each tool offers, keep it in an environment variable rather than the database, and know how you'd rotate it.
