Is Drupal 7 affected by CVE-2026-108097 (SA-CORE-2026-014)?
Drupal 7 core isn't exploitable through CVE-2026-108097. Here's how we tested Field UI and why NES for Drupal 7 ships hardening anyway.
_.png)
Drupal 7 core is not exploitable through CVE-2026-108097 / SA-CORE-2026-014, the critical remote code execution vulnerability in Field UI that the Drupal Security Team published on October 14, 2026. Drupal 7 has the same kind of code, so we tested it on a live site, and three separate safeguards blocked every attempt. We also checked the contrib modules that work with these screens and found none that opens a path to it. We hardened NES (Never-Ending Support) for Drupal 7 anyway, as a precaution. Below: what the advisory covers, how we tested NES for Drupal 7, and why we shipped a fix for a bug we couldn't exploit.
What is CVE-2026-108097 (SA-CORE-2026-014)?
On October 14, 2026, the Drupal Security Team published SA-CORE-2026-014, tracked as CVE-2026-108097. It's a remote code execution vulnerability in Drupal core's Field UI module, the code behind the "Manage fields" and "Manage display" screens that site builders use to arrange a content type's fields.
It's rated critical, with a risk score of 19 out of 25. Affected versions run from Drupal 8.9.0 through the current 10.x, 11.x and 12.0 pre-releases.
The interesting part of this advisory is what it says about core. Core alone can't be exploited directly. The danger comes from contributed modules, which create several serious exploit paths, and at least one of them doesn't require authentication. The advisory also warns that custom code may expose the flaw.
For Drupal 7, that's the worst kind of advisory to get. "Core is vulnerable, here's the patch" is easy to act on. "Core is fine, but your modules might not be" means somebody has to go look at the modules.
Why the advisory doesn't mention Drupal 7
Drupal 7 reached community end-of-life on January 5, 2025, and we've covered what that timeline means before. The Drupal Security Team doesn't audit advisories against it anymore, and that's expected. They're volunteers, and their scope ends at the supported branches.
So SA-CORE-2026-014 doesn't say Drupal 7 is vulnerable, and it doesn't say Drupal 7 is safe. It just doesn't say. That's the gap we fill for our customers on every core advisory.
This one needed more than a read of the patch. Drupal 7 has the same pattern in the same module. When Field UI draws one of those tables, it asks each row which region the row belongs in by calling a function the row names. Core calls whatever name it finds, without checking it. If an attacker could control that name, they could make Drupal run something like system() or exec(), which are PHP's own functions for running commands on the server.
The code is there. What we needed to know was if anyone could reach it.
How we tested Drupal 7 against CVE-2026-108097
We set up a clean Drupal 7.103 site, the last community release and the base of NES, and treated the advisory as if Drupal 7 were affected until we could prove otherwise.
First, we proved the dangerous call is real. We wrote a small test module that puts a harmless "canary" function into a row, one that only writes a line to a log file. The canary fired. If code sets that value, Drupal 7 will call it.
Then we tried to get there from the outside. We sent requests to both screens, including the AJAX endpoint the screens use, with the value injected into the form body and the query string. Three separate safeguards stopped every attempt:
- Core removes request keys that start with # before anything else sees them. Our injected keys were removed and logged before they reached the form.
- We turned that first safeguard off and tried again. The canary still didn't fire. Drupal 7's Form API never copies submitted data onto these parts of the form, so the first layer isn't the only thing holding.
- Both pages require the "administer fields" permission. Anonymous requests get a 403. We also tried replaying an admin's form ID as an anonymous user, and Drupal rejected it.
If that first safeguard sounds familiar, it should. It's the fix for Drupalgeddon 2 (SA-CORE-2018-002), the 2018 remote code execution bug in Drupal 7. Drupalgeddon 2 was the same kind of problem. Drupal's render arrays have # properties that name functions to call later, and attackers could slip their own into a request. Send something like mail[#post_render][]=exec to the registration form, and an anonymous visitor could run commands on the server. Drupal 7.58 closed that by stripping # keys from every request. Eight years later, it's still doing its job.
Core was the easy half. The advisory says the real exploit paths are in contrib, so that's where we spent most of our time.
We looked at Field Group and Display Suite first. They're the two most widely used modules that build on these screens, and both set their own region callbacks. Every one of those is a fixed function name in the module's code. None of it comes from user input or stored settings.
Two modules felt like too small a sample, so we downloaded the latest Drupal 7 releases of 30 popular contrib projects that work with Field UI and searched their code. None of them sets a region callback at all.
Drupal 7 core is not exploitable through CVE-2026-108097
We couldn't find a way to exploit SA-CORE-2026-014 in Drupal 7 core, and the contrib modules we checked don't open one.
We can't say that about every module on every Drupal 7 site. There are thousands of contrib modules and far more custom ones. That's exactly the scenario the upstream advisory describes. A module with its own bug could, in theory, still hand an attacker that row value. That's why we didn't stop at "not affected."
Why we hardened NES for Drupal 7 anyway
Upstream fixed this by removing the callback entirely and reading the region from the form. That works in modern Drupal. In Drupal 7, core's own rows don't have that form element, and Field Group and Display Suite depend on their callbacks working. A straight port would break those modules until someone updated them.
We set a hard rule for ourselves: if this change requires a single customer, custom module or contrib module to change a line of code, it's a failure. The only acceptable visible difference is a log message when something is actually wrong.
We also considered an allowlist of known-good callbacks. It would have been tidy, and it would have broken every custom module whose callback wasn't on the list. That's the same failure with extra steps.
Here's what we shipped instead. Every legitimate region callback is a function written by a module, because it has to understand a Drupal table row. Every dangerous target, like system(), exec() and assert(), is a function built into PHP itself. Nobody has a valid reason to use one of PHP's built-ins there. So before Field UI calls a region callback, NES now checks whether PHP wrote it or a module did.
If it's a built-in PHP function, NES for Drupal 7 doesn't call it. The screen still loads with the bad row left out, and it writes an error to the site's log using Watchdog, naming the function and the row. Everything else runs exactly as it did before.
However, PHP gives you more than one way to name a function. Class methods, closures and catch-all methods can all point back to a built-in. Fortunately, this check follows each of them to the code that would actually run.
That last point is where a second set of eyes earned its keep. After our first version passed its tests, another review found a way to name a built-in function that wasn’t initially considered. We fixed it, added tests for it, and re-ran everything. It's the same lesson we learned from the Webform backports: the first version that passes its tests isn't necessarily the version you ship.
How we know the NES fix doesn't break anything
We didn't want to assume the change was safe for existing sites, so we measured it.
We scripted the same set of actions on both screens and ran it before and after the change: loading the page, the AJAX updates, a save that fails validation, a successful save, and reading back the settings it stored. Then we compared the two runs line by line. We did this with core alone, with Field Group and Display Suite, and then with five more modules that change these tables in different ways: Renderable elements (rel), Multifield, Field Collection, Display Cache, and Field Formatter Settings with Linked Field.
On PHP 5.6, 7.4 and 8.2, the two runs produced the same output. The site logs were identical too, and the new check didn't log anything during normal use.
We also tested what happens when something is wrong. On PHP 8.2, unpatched Drupal 7 crashes the whole admin page with a 500 error when a row names a built-in function. With NES, the page loads without that row and logs one clear message. On 5.6 and 7.4, the page looks the same as it did before, and the one log message replaces a PHP warning that was easy to miss.
The change ships with new automated tests that cover the cases above, and all of the existing Field UI tests still pass on every PHP version we tested.
What this hardening doesn't do
I want to be clear about the limits, because this is defense in depth and it has gaps.
The check removes the most dangerous targets, PHP's own built-in functions. It doesn't judge whether a function written by a module is safe to call with a table row. An attacker would also still need a separate bug in some module just to set that value in the first place, and we didn't find one.
Upstream fixed this by dropping the callback and reading the region straight from the form. That works in modern Drupal. In Drupal 7 it would break Field Group, Display Suite and any custom module with its own region callback, and we refuse to ship changes that break customer sites. So we went after what an exploit actually needs instead. NES for Drupal 7 won't call PHP's built-in functions from this spot, and every module that uses these screens keeps working. Core still has no known path to this code. The new check is there in case some other module ever opens one.
NES customers: you're covered
Drupal 7 core isn't exploitable through SA-CORE-2026-014, and no emergency action is required. The hardening ships in the next NES for Drupal 7 release. Apply it the way you apply any other update. There's nothing to configure, no database update, and no module changes needed.
If you ever see a field_ui error in your site log saying a region callback was refused, it means some code on your site tried to do something it shouldn't. That's worth a look from your developer. In normal use, you'll never see it.
Running Drupal 7 without extended support?
The advisory says core alone isn't exploitable, but contrib is. For a Drupal 7 site, that's the hardest kind of advisory to sit with. There's no Drupal 7 patch, and the risk depends on code nobody has checked for you.
Someone has to do that work on every advisory. For our customers, that's us. You can see the running log of CVEs fixed in our vulnerability directory.
Talk to us about NES for Drupal 7 →
Resources
View All Articles


