NEWS
Checkout Files Upload for WooCommerce lets anyone upload PHP. See whether yours is affected
Security

Headless WordPress and security, what actually changes

# TagsHeadlessSecurity
The WPhost team16 min read

If you are considering a headless store, you have probably heard that it is "more secure". That is partly true. Headless WordPress does change security, because the public side of the site is no longer WordPress, but it does not settle the question for good. Some risks shrink, and the rest are joined by the risks of a new system.

This guide separates the two sides honestly. We first look at what really changes, then at what stays the same, and finally at the vulnerabilities of Next.js itself and the secret keys that connect the two parts. The checklist at the end helps you check your current site or ask your developer the right questions.

What headless WordPress is, briefly

In classic WordPress one system does everything. It holds the content and builds every page with PHP on each visit, and the admin lives in the same place. Headless splits these roles. The public side is a separate application, in our case built on Next.js, which takes the content from WordPress through an API (an interface the two systems use to exchange data) and prepares the pages in advance. WordPress stays for running the site, and in a store WooCommerce keeps holding the products and orders.

When this model is worth it and when it is not is covered in the guide to headless WordPress with Next.js. Here we look only at security.

What actually changes

Visitors do not reach WordPress

The pages of a headless site are usually prepared in advance, so opening them does not run PHP and the WordPress database for every visitor. The WordPress theme is not shown anywhere, and the plugins for the public side, such as page builders and sliders, are no longer needed, because Next.js builds the pages. Delete them. A plugin that is not there cannot have a vulnerability.

There is an important detail here. As long as a plugin is installed and WordPress is reachable from the internet, its code can be called directly at the WordPress address, even if the public site never uses it. The real gain comes when you remove the unneeded code and limit who can reach WordPress.

The admin and the API can be hidden

Visitors no longer open WordPress, so it does not have to be reachable by the whole internet. There are three common ways to limit it.

  • An allowlist of addresses. The server accepts requests to WordPress only from the IP addresses of the Next.js server and the office.
  • An access gateway. Every request to the admin first goes through a service that asks for a company login and, optionally, a second factor.
  • A VPN. Editors connect to a private network and only then open the admin.

What exactly you close matters. The Next.js server has to reach the WordPress API to fetch content, and editors have to reach the admin. If the shopper's browser talks to WooCommerce directly, for example for the cart, those addresses stay public. WooCommerce's Store API is made for exactly that and works without a login. When the cart and the orders go through the Next.js server, WordPress can be closed to everyone else.

WordPress itself recommends an extra server-level password on /wp-admin/ as a second layer, and warns that it can break functions that rely on admin-ajax.php. With headless the public site does not use them, so that risk is much smaller. In the headless stores we build, the admin can be hidden from the internet, and how far that goes depends on how the editors work and on the outside services that send data to WordPress.

XML-RPC can be closed completely

XML-RPC is an old WordPress interface that Next.js does not use. A classic site sometimes keeps it for Jetpack or mobile publishing apps, but with headless you can close the xmlrpc.php file on the server, as shown in the guide to securing a WordPress site. The xmlrpc_enabled filter in WordPress is not enough, because it only stops the methods that require a login.

What does not change

WordPress and its plugins still need updates

Headless does not make WordPress invulnerable. According to Patchstack's annual report, 11,334 new vulnerabilities were found in the WordPress ecosystem in 2025, 91% of them in plugins and 9% in themes, with only 6 in core. A headless store has fewer plugins, but WooCommerce stays, along with the plugins the store really needs, for example for invoices or couriers.

A hidden admin lowers the risk, because an attacker cannot reach the vulnerable code, but it does not remove it. Data from the storefront, such as an order with a delivery address, still enters WooCommerce and passes through plugin code. An editor with a stolen password who logs in from an allowed address or through the VPN also reaches the admin. That is why updates remain the most important protection with headless too. Update WordPress and the plugins in time, after a check in staging.

The REST API shows more than you expect

The REST API is how Next.js reads content from WordPress. By design it is an open interface that shows published content to anyone who asks. That is normal, but there are two details.

The first is the user list. The /wp-json/wp/v2/users address shows anyone, without a login, the users who have published content, with their name and slug. WordPress makes the slug from the username when the account is created, so it usually gives away the login name.

The second is plugins. Every plugin can add its own addresses to the API. Since version 5.5 WordPress warns the developer when an address is registered without a permission check, but the warning does not stop the address, and it stays public.

Switching the REST API off is no solution, because WordPress uses it in the admin too, and a headless site would have nowhere to get its content from. Limit who can reach the API if the storefront can read it from the server, or close the individual addresses that are not needed. Check what a stranger sees with two read-only commands.

Bash
# Your computer, outside the office and off the VPN. Read-only.
curl -s --max-time 10 https://cms.primer.bg/wp-json/wp/v2/users \
  | head -c 300; echo
curl -s -o /dev/null --max-time 10 -w '%{http_code}\n' \
  https://cms.primer.bg/wp-login.php

Replace cms.primer.bg with the address WordPress runs on. If the first command shows a list of names and slugs, anyone can read the API. If the second returns 200, the login page is reachable from the internet. With restricted access you will see 401 or 403, while 000 means the server did not answer at all, which is also a good sign.

Next.js has its own vulnerabilities

The Next.js storefront is code that runs on a server, and like all code it has vulnerabilities. Two of them were critical in 2025, and they show why this part needs regular updates too.

CVE-2025-29927, bypassing checks in middleware

On 21 March 2025 a vulnerability in Next.js was published with a CVSS score of 9.1, which is critical. Access checks placed in middleware (code that runs before the pages) could be bypassed with one special header in the request. Versions from 11.1.4 onwards were affected, up to the fixed 12.3.5, 13.5.9, 14.2.25 and 15.2.3. Self-hosted applications started with next start or with output: 'standalone' were vulnerable, and statically exported sites were not.

The lesson goes beyond this one bug. Next.js now explicitly advises doing login and permission checks inside every function that changes data, instead of relying on middleware alone. Since version 16, middleware is called proxy.

CVE-2025-55182, running someone else's code through React Server Components

On 3 December 2025 the React team announced a vulnerability with the maximum CVSS score of 10. A specially crafted request could make the server run an attacker's code without any login. The flaw was in React Server Components, versions 19.0.0, 19.1.0, 19.1.1 and 19.2.0, and the fix came in versions 19.0.1, 19.1.2 and 19.2.1. Two days later the US cybersecurity agency CISA added it to its catalogue of vulnerabilities already used in attacks.

In Next.js, App Router applications on versions 15 and 16 were affected, while Next.js 13, stable version 14 and Pages Router applications were not. There was no workaround, only updating. Fixes for related vulnerabilities followed later, so today the target is the latest version in your Next.js release line. After updating, Next.js also recommended rotating all the secret keys of applications that had been online and unpatched as of 4 December.

npm packages

Besides Next.js and React, the application depends on many other packages from npm, the package registry for JavaScript. A vulnerability in any of them is a vulnerability in the store. The two commands below show the versions and the known vulnerabilities. Run them in the project folder or ask your developer to send you the output.

Bash
# In the Next.js project folder. They do not change any files.
npm ls next react
npm audit --omit=dev

The second sends the list of packages to the npm registry and returns the known vulnerabilities in them. Do not run npm audit fix --force without checking, because it can move a package to a new major version that breaks the application. If the code is on GitHub, turn on Dependabot alerts to get a warning when a package has a known vulnerability.

Also keep an eye on which major version of Next.js you run. Security fixes go only to the current and the previous major version, each for up to two years after its release. Under the Next.js policy, version 14 and older are no longer supported, and fixes for them come out only as exceptions.

The secrets that connect the two parts

The two parts of a headless site have to trust each other, so there are secret keys between them. One is the WooCommerce REST API key the storefront uses to create orders, another an Application Password in WordPress. Whoever holds these keys can do everything the storefront does.

  • Secrets stay on the server. In Next.js, environment variables that start with NEXT_PUBLIC_ are built into the code that goes to the browser, and anyone can read them. Keys for WordPress and WooCommerce must never have such a name.
  • .env files stay out of Git. Next.js warns that you almost never want to commit them to the repository, and the create-next-app template excludes them by default.
  • Each key has only the permissions it needs. WooCommerce creates keys with Read, Write or Read/Write permissions, and a key that only reads products should not be able to write. The secret part of the key is shown only once, so store it straight where the server keeps its secrets.
  • Keys can be rotated quickly. When someone leaves the team or a key leaks somewhere, rotating it should take minutes and not stop the store. Sometimes the vendor recommends it too, as Next.js did after CVE-2025-55182.

Updates and monitoring on both sides

On a classic site you update one system. With headless there are two, each at its own pace.

  • WordPress. Core, plugins and theme. WordPress has installed minor core versions on its own since 3.7, but plugins and the theme wait for you or for your maintenance.
  • Next.js and npm. Next.js itself, React and the other packages. Here an update means a new build and a new release of the application, and there is no button in the admin.

On both sides a change should go through Git and staging before it reaches the live site, with a rollback plan.

Monitoring has to cover both parts as well. Watch whether the storefront answers, whether the WordPress API answers the Next.js server, how many failed login attempts the admin gets and whether creating orders throws errors. If WooCommerce stops answering, the storefront can keep serving pages from cache and the problem can go unnoticed. In our model orders wait in a queue and are not lost, but even then monitoring has to catch the problem in time.

Backups remain essential. The WordPress database holds the products and orders, and the storefront's code is in Git. How to make and test a backup is covered in the WordPress backup guide.

Checklist

  • Unneeded plugins for the public side are deleted from WordPress.
  • The WordPress admin and API are reachable only by the Next.js server and the editors, or the reason they are not is written down.
  • xmlrpc.php is closed on the server.
  • /wp-json/wp/v2/users does not show strangers a list of users.
  • WordPress and its plugins are updated in time, after a check in staging.
  • Next.js is on a supported major version and the latest fix in its line.
  • npm audit --omit=dev shows no critical vulnerabilities.
  • No secret sits in a NEXT_PUBLIC_ variable or in a file in Git.
  • WooCommerce keys have only the permissions they need and can be rotated quickly.
  • Monitoring watches the storefront, the WordPress API and the orders, and backups are tested with a restore.

Who watches all this every day

If your store runs on classic WordPress and works well, you do not need to move to headless for security. Most of the protections in the guide to securing a WordPress site apply there too.

If you have a headless site or are considering one, what matters most is that someone watches both sides. Under active maintenance we check your plugins, theme and WordPress against the known vulnerability (CVE) databases every day and update them in time, after a test in staging. How that works is described under vulnerability monitoring. If you are building a new store, in our headless online store development the admin can be hidden from the internet, and security keeps going after the launch.

Frequently asked questions

Is headless WordPress more secure than classic WordPress?

Partly. Visitors see a Next.js application and never reach WordPress, so the admin and the API can be restricted, and plugins for the public side are no longer needed. WordPress and its plugins still need updates, though, and the remaining risks are joined by those of a new system, Next.js and the npm packages.

How can the WordPress admin be hidden on a headless site?

There are three common ways. The server can accept requests to WordPress only from the IP addresses of the Next.js server and the office, every request to the admin can go through an access service with a company login first, or editors can connect through a VPN. If the shopper's browser talks to WooCommerce directly, for the cart for example, those addresses stay public, so WordPress can be closed to everyone else when the cart and orders go through the Next.js server.

Do I still need to update WordPress and plugins on a headless site?

Yes. According to Patchstack's annual report, 11,334 new vulnerabilities were found in the WordPress ecosystem in 2025, 91% of them in plugins. A hidden admin lowers the risk, but data from the storefront, such as an order with a delivery address, still enters WooCommerce and passes through plugin code, so updates remain the most important protection.

What does the WordPress REST API show to strangers?

By design the REST API shows published content to anyone who asks. The address /wp-json/wp/v2/users shows, without a login, the users who have published content, with their name and slug, which usually gives away the login name. Plugins can also add their own addresses without a permission check, and those stay public.

Can I just switch off the REST API?

No. WordPress uses the REST API in the admin too, and a headless site would have nowhere else to get its content from. Limit who can reach the API if the storefront can read it from the server, or close the individual addresses you do not need.

What were the critical Next.js vulnerabilities in 2025?

CVE-2025-29927 of 21 March 2025, scored 9.1 on CVSS, let access checks in middleware be bypassed with one special header in the request. CVE-2025-55182 of 3 December 2025, with the maximum score of 10, allowed running someone else's code without a login through React Server Components, and CISA added it to its catalogue of exploited vulnerabilities two days later. In both cases the fix was updating.

How do I protect the secret keys between WordPress and Next.js?

Keys stay on the server, because in Next.js environment variables starting with NEXT_PUBLIC_ are built into the code sent to the browser, where anyone can read them. .env files stay out of Git, and each key has only the permissions it needs, so a WooCommerce key that only reads products should not be able to write. Rotating a key should take minutes and not stop the store.

Which Next.js versions get security fixes?

Security fixes go only to the current and the previous major version of Next.js, each for up to two years after its release. Under the Next.js policy, version 14 and older are no longer supported, and fixes for them come out only as exceptions. Beyond Next.js itself, run npm audit in the project folder or turn on Dependabot alerts on GitHub to hear about vulnerable packages.

Sources

# TagsHeadlessSecurity