Like a loaded gun in a locked safe — the trigger is in core, but someone else has to open the door
CVE-2026-108097 is a remote code execution flaw in Drupal core's Field UI module (field_ui), disclosed on 14 October 2026 as SA-CORE-2026-014. The root cause is a missing validation on the #region_callback element in Field UI's table render array: any PHP callable placed in that slot is executed directly with no is_callable() check, no allow-list, and no signature restriction. The vulnerability spans an enormous range — Drupal 8.9.0 through 10.6.18, 11.0.0 through 11.3.18, 11.4.0 through 11.4.9, and 12.0.0-alpha1 through beta1. Fixed releases are 10.6.19, 11.3.19, 11.4.10, and 12.0.0-beta2; Drupal 7 is patched in 7.107.
Tenable stamps this at CVSS 9.8 Critical (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H), and Drupal rates it 19/25 Critical on their own scale. But both scores overstate real-world exploitability for most sites. The crucial detail buried in the advisory is: core alone is not directly exploitable. The vulnerable callback sits behind authenticated admin routes (Manage Display forms). Reaching it without auth requires a contributed or custom module that passes request data into that render array — and FORTBRIDGE, who published the definitive PoC, explicitly could not find a genuine public contributed module that creates this path. They had to write a synthetic bridge module for their lab chain. That friction is meaningful. The severity is real — when the chain connects, you get unauthenticated RCE — but the precondition narrows the exploitable population far below what a 9.8 implies.
5 steps from start to impact.
Identify Drupal target and version
X-Drupal-Cache headers, or session cookie names. Version is extracted from /core/CHANGELOG.txt or generator tags. The ExDev994 weaponized tool includes FOFA dorks for bulk reconnaissance. Over 151,000 sites were running vulnerable versions as of disclosure.- Target runs Drupal 8.9.0–10.6.18, 11.0–11.3.18, 11.4.0–11.4.9, or 12.0.0 pre-beta2
- ~50% of Drupal assets hide version indicators per CyCognito data
- Version alone does not confirm exploitability — contributed module is still required
Probe for contributed module entry point
#region_callback slot. FORTBRIDGE's research confirmed that core's own Field UI routes are admin-only and reject unauthenticated requests. The attacker scans for known module routes (e.g., Entity List views, custom field-display endpoints) or fuzzes for render array injection points.- Target must have a contributed/custom module that bridges unauthenticated input to the vulnerable render path
- FORTBRIDGE found no public contributed module that creates this path — they used a synthetic bridge module
- The Entity List module (most similar match) was patched separately as CVE-2026-108099
- Custom code creating this pattern exists but prevalence is unknown and likely low
Inject malicious PHP callable via #region_callback
#region_callback render array element. Because Field UI performs zero validation on this value — no is_callable() check, no allow-list — any PHP callable (including system, passthru, exec, or arbitrary class methods) is accepted and queued for execution during table rendering.- Unauthenticated route from Step 2 passes attacker input to the render array
- PHP callable injection is unfiltered
- Some WAFs may block obvious PHP function names in POST/GET parameters
- Drupal Steward's WAF rules cover *known* vectors but not all possible module entry points
disable_functions may block common callables but determined attacker uses alternatives.Achieve file disclosure
settings.php containing database credentials, hash salts, and potentially API keys). This is the file-disclosure stage of the ExDev994 multi-stage pipeline.- Successful callable injection from Step 3
- PHP process has read access to target files
- SELinux/AppArmor policies may restrict PHP process file reads
- Containerized deployments may limit accessible filesystem
Escalate to remote code execution
system() or equivalent for OS command execution. The result is a web shell or direct command output — full RCE as the web server user (typically www-data or apache). FORTBRIDGE confirmed the full chain: file disclosure to command execution, no authentication required.- All prior steps succeed
- PHP
disable_functionsdoes not block all execution primitives
- Hardened PHP configurations with restrictive
disable_functionslists may block direct command execution - Container environments may limit lateral movement from the web server user
field_ui module provides admin UI for managing fields and display modes — it is not needed at runtime on production sites. Removing it eliminates the vulnerable callback entirely. Run drush pm:uninstall field_ui or remove from config. Deploy within 30 days per the noisgate mitigation SLA for HIGH, but given the weaponized PoC, doing this within 72 hours is strongly recommended.field_ui (e.g., content teams actively use it in production), deploy WAF rules that block unauthenticated access to routes containing /admin/structure/, /field-ui/, and any contributed module routes that expose table rendering. Drupal Steward provides partial coverage for known vectors. This reduces but does not eliminate risk — unknown contributed module entry points may bypass route-based rules.system, exec, passthru, shell_exec, proc_open, popen, pcntl_exec to PHP's disable_functions in php.ini. This breaks the RCE stage of the chain even if the callable injection succeeds — the attacker can still achieve file disclosure but cannot execute OS commands. Apply across all Drupal PHP-FPM pools.- Restricting admin access via IP allowlist alone — The unauthenticated exploitation path goes through contributed module routes, not admin routes. IP-restricting
/admin/*does not block the contributed module entry point. - Updating contributed modules only — The vulnerability is in Drupal *core's* Field UI, not in any specific contributed module. Patching Entity List (CVE-2026-108099) closes one path but the core flaw remains exploitable via other bridges.
- PHP
open_basedirrestrictions — While this limits file disclosure scope, it does not prevent the callable injection or command execution stages. The attacker can still achieve RCE within the allowed directory tree.
The supporting signals.
| In-the-wild exploitation | No confirmed exploitation as of 22 Oct 2026. Not on CISA KEV. Drupal marked exploit maturity as E:Theoretical at disclosure but warned exploits could emerge 'within hours or days.' |
|---|---|
| Proof-of-concept | Multiple PoCs public. FORTBRIDGE (Adrian Tiron) published full technical analysis + lab exploit code. ExDev994/CVE-2026-108097 is a weaponized Python3 multi-stage tool (detect → write → sink → callable leak → file disclosure → RCE) with FOFA dorks. FurkanKAYAPINAR/CVE-2026-108097 is a defensive detector. Sploitus indexes ≥2 exploit entries. Critical caveat: all PoCs require a bridge module — no public contributed module enables the unauth chain. |
| EPSS score | Not yet scored by FIRST (empty result from EPSS API as of 22 Oct 2026). CVE is only 8 days old; EPSS typically populates within 30 days. |
| KEV status | Not listed. No CISA Known Exploited Vulnerabilities entry as of 22 Oct 2026. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H (9.8 Critical) per Tenable/NVD. Drupal's own scale: 19/25 Critical (AC:Basic/A:None/CI:All/II:All/E:Theoretical/TD:Default). Both assume the unauth path is reachable — which requires a contributed module. |
| Affected versions | Drupal core 8.9.0–10.6.18, 11.0.0–11.3.18, 11.4.0–11.4.9, 12.0.0-alpha1 through beta1. Drupal 7 < 7.107 also affected. |
| Fixed versions | 10.6.19, 11.3.19, 11.4.10, 12.0.0-beta2, 7.107 (LTS). Released 14 October 2026. Drupal 8.x and 9.x are EOL — no patches available. |
| Exposure surface | 151,000+ Drupal sites (28.5% of reporting sites) running vulnerable versions per CyCognito. Sectors: Consumer Staples (30.5%), Industrials (27.4%). ~50% of assets hide version. Geo concentration: US, Netherlands, Germany. |
| Disclosure timeline | Disclosed 14 Oct 2026 (SA-CORE-2026-014). FORTBRIDGE technical writeup + PoC followed within days. ExDev994 weaponized tool published 20 Oct 2026. |
| Researcher / reporter | Drupal Security Team (advisory). Adrian Tiron / FORTBRIDGE (PoC + technical analysis). ExDev994 (weaponized exploit tool). |
Sources.
- Drupal SA-CORE-2026-014 (Official Advisory)
- BleepingComputer — Drupal patches critical RCE flaws
- SecurityOnline — Technical Details and PoC Published
- CyCognito — Emerging Threat Analysis
- SOCRadar — Drupal Patches Critical RCEs
- Tenable — CVE-2026-108097
- FurkanKAYAPINAR/CVE-2026-108097 (Defensive Detector)
- Sploitus — ExDev994 Weaponized PoC
Why this verdict
- Contributed module gate is real friction. The CVSS 9.8 assumes direct unauthenticated exploitation, but Drupal's own advisory and FORTBRIDGE's research both confirm core alone is not directly exploitable. The vulnerable callback sits behind admin-only routes. An unauthenticated path requires a contributed or custom module that bridges user input to the render array — and FORTBRIDGE explicitly found no genuine public contributed module that does this. This materially narrows the exploitable population.
- PoC is weaponized but bridge-dependent. ExDev994's Python tool is a full pipeline (detect → RCE), but it still needs a target-side module that creates the unauthenticated entry point. Without that bridge, the tool's scan stages will find the Drupal version but fail at the sink-probing stage. The PoC proves the *mechanism* but not mass exploitability.
- No active exploitation or KEV listing. Eight days post-disclosure with weaponized PoC available, there are zero confirmed in-the-wild incidents. Drupal marked exploit maturity as Theoretical. CISA has not added it to KEV. This suggests the contributed module requirement is a genuine barrier, not a theoretical one.
- Role multiplier: Drupal is a web application CMS, not canonical infrastructure (not a hypervisor, domain controller, IdP, PAM, or network edge appliance). (a) *Low-value role:* dev/staging sites, personal blogs — compromise is nuisance-level. (b) *Typical role:* corporate marketing sites, content portals — compromise yields web server access + database credentials (PII, session tokens), blast radius is application-tier. (c) *High-value role:* government portals, e-commerce sites handling PII/payment data, intranet portals with SSO integration — compromise could yield regulated data and pivot opportunities. However, even in the high-value role, the blast radius is host→application, not domain→fleet. Drupal compromise does not inherently give domain admin, fleet control, or supply-chain pivot. The high-value outcome (data exfiltration from a government portal) warrants HIGH but not CRITICAL given the contributed module gate.
- Large but uncertain exposure surface. 151K+ vulnerable sites is significant, but the *exploitable* subset (those with the right contributed/custom module) is unknown and likely a small fraction. The uncertainty prevents going lower than HIGH — some non-trivial number of sites probably have custom code that inadvertently creates the bridge.
Why not higher?
The contributed module requirement is not a theoretical defense — it is a validated friction point confirmed by the researcher who wrote the PoC. FORTBRIDGE explicitly could not find a public module that enables the unauth chain. Core-only Drupal installations are not exploitable. Drupal is not a canonical high-value infrastructure component (not a DC, hypervisor, IdP, or network edge), so the deployment-role floor does not mandate CRITICAL. No active exploitation exists despite 8 days of public PoC availability.
Why not lower?
The vulnerability *mechanism* is confirmed: when the bridge exists, the chain delivers unauthenticated RCE with no user interaction — the most severe outcome class. Weaponized tooling is public and includes bulk-scanning capability (FOFA dorks). 151K+ sites are running vulnerable versions. The contributed module requirement is friction, not an impenetrable barrier — custom code on Drupal sites is common, and the specific pattern (feeding request data into render arrays) is a plausible development mistake. Drupal's own security team rated this Critical and issued advance warning. Dropping below HIGH would undercount the risk to the fraction of sites that do have the bridge.
Crowdsourced verification payload.
Run this script on each Drupal web server host as the user that owns the Drupal codebase (or root). It checks the Drupal core version against patched releases and whether field_ui is enabled. Example: chmod +x check_cve_2026_108097.sh && ./check_cve_2026_108097.sh /var/www/html where the argument is your Drupal docroot. No special privileges needed beyond read access to the Drupal filesystem.
#!/usr/bin/env bash
# check_cve_2026_108097.sh — Detect CVE-2026-108097 (Drupal Field UI RCE)
# Usage: ./check_cve_2026_108097.sh /path/to/drupal/docroot
# Exit codes: 1=VULNERABLE, 0=PATCHED, 2=UNKNOWN
set -euo pipefail
DOCROOT="${1:-}"
if [ -z "$DOCROOT" ] || [ ! -d "$DOCROOT" ]; then
echo "UNKNOWN — Usage: $0 /path/to/drupal/docroot"
exit 2
fi
# Detect Drupal major version and core version
VERSION=""
if [ -f "$DOCROOT/core/lib/Drupal.php" ]; then
# Drupal 8/9/10/11/12
VERSION=$(grep -oP "const VERSION = '\K[^']+" "$DOCROOT/core/lib/Drupal.php" 2>/dev/null || true)
elif [ -f "$DOCROOT/includes/bootstrap.inc" ]; then
# Drupal 7
VERSION=$(grep -oP "define\('VERSION', '\K[^']+" "$DOCROOT/includes/bootstrap.inc" 2>/dev/null || true)
fi
if [ -z "$VERSION" ]; then
echo "UNKNOWN — Could not detect Drupal version at $DOCROOT"
exit 2
fi
echo "Detected Drupal version: $VERSION"
# Check if field_ui is enabled (Drupal 8+)
FIELD_UI_ENABLED="unknown"
if [ -f "$DOCROOT/sites/default/settings.php" ]; then
# Check via core.extension.yml if it exists
EXTENSION_FILE=$(find "$DOCROOT/sites" -path '*/sync/core.extension.yml' -o -path '*/config/core.extension.yml' 2>/dev/null | head -1)
if [ -n "$EXTENSION_FILE" ] && [ -f "$EXTENSION_FILE" ]; then
if grep -q 'field_ui:' "$EXTENSION_FILE" 2>/dev/null; then
FIELD_UI_ENABLED="yes"
else
FIELD_UI_ENABLED="no"
fi
fi
# Also check if the module directory exists and is reachable
if [ -d "$DOCROOT/core/modules/field_ui" ]; then
if [ "$FIELD_UI_ENABLED" = "unknown" ]; then
FIELD_UI_ENABLED="module_present_status_unknown"
fi
fi
fi
# Version comparison function
version_gte() {
[ "$(printf '%s\n' "$1" "$2" | sort -V | head -1)" = "$2" ]
}
# Determine vulnerability status based on version
VULNERABLE=false
MAJOR=$(echo "$VERSION" | cut -d. -f1)
MINOR=$(echo "$VERSION" | cut -d. -f1-2)
case "$MAJOR" in
7)
if version_gte "$VERSION" "7.107"; then
VULNERABLE=false
else
VULNERABLE=true
fi
;;
8|9)
# EOL — no patch available, always vulnerable
VULNERABLE=true
echo "WARNING: Drupal $MAJOR.x is end-of-life. No patch available."
;;
10)
if version_gte "$VERSION" "10.6.19"; then
VULNERABLE=false
elif version_gte "$VERSION" "8.9.0"; then
VULNERABLE=true
fi
;;
11)
if echo "$VERSION" | grep -qP '^11\.4\.'; then
version_gte "$VERSION" "11.4.10" && VULNERABLE=false || VULNERABLE=true
elif echo "$VERSION" | grep -qP '^11\.[0-3]\.'; then
version_gte "$VERSION" "11.3.19" && VULNERABLE=false || VULNERABLE=true
else
VULNERABLE=true
fi
;;
12)
if echo "$VERSION" | grep -q 'alpha\|beta1'; then
VULNERABLE=true
else
VULNERABLE=false
fi
;;
*)
echo "UNKNOWN — Unrecognized Drupal major version: $MAJOR"
exit 2
;;
esac
if [ "$VULNERABLE" = true ]; then
echo "field_ui module status: $FIELD_UI_ENABLED"
if [ "$FIELD_UI_ENABLED" = "no" ]; then
echo "PATCHED — Version $VERSION is in the vulnerable range, but field_ui is disabled (workaround active)."
exit 0
else
echo "VULNERABLE — Drupal $VERSION is affected by CVE-2026-108097 (SA-CORE-2026-014)."
echo "Remediation: Upgrade to 10.6.19 / 11.3.19 / 11.4.10 / 12.0.0-beta2+ or uninstall field_ui."
exit 1
fi
else
echo "PATCHED — Drupal $VERSION is not affected by CVE-2026-108097."
exit 0
fi