This is a breaker switch an outsider can keep flipping until your front door stops working
CVE-2026-0227 is an unauthenticated network DoS in PAN-OS GlobalProtect Gateway and Portal. A remote attacker can send crafted traffic to an exposed GlobalProtect service and repeatedly trigger a failure condition until the firewall drops into maintenance mode. It only applies when GlobalProtect gateway or portal is enabled. Palo Alto says affected ranges include PAN-OS 12.1 before 12.1.3-h3/12.1.4, 11.2 before 11.2.4-h15/11.2.7-h8/11.2.10-h2, 11.1 before 11.1.4-h27/11.1.6-h23/11.1.10-h9/11.1.13, 10.2 before 10.2.7-h32/10.2.10-h31/10.2.13-h18/10.2.16-h6/10.2.18-h1, and 10.1 before 10.1.14-h20; Cloud NGFW is not affected and Prisma Access was vendor-upgraded.
Vendor HIGH is basically fair, but only if you keep the deployment context in view. This is pre-auth and low-complexity against a perimeter service, which keeps it out of MEDIUM territory. But it is availability-only, there is no known malicious exploitation as of the vendor advisory, and there is a hard exposure gate: no enabled GlobalProtect, no issue. That keeps it below CRITICAL even though the affected component often sits on the public internet.
4 steps from start to impact.
Find an exposed GlobalProtect edge
curl or a custom fingerprinting script.- Target exposes GlobalProtect gateway or portal to the attacker
- Affected PAN-OS branch/version is deployed
- If GlobalProtect is disabled, internally scoped, or IP-restricted, the attack path dies immediately
- Cloud NGFW is unaffected and Prisma Access customers were vendor-upgraded
Send the crash-triggering request sequence
- No authentication required
- Network path to the GlobalProtect service
- Traffic can reach the service without being filtered upstream
- Upstream rate limiting, DDoS controls, or allowlists can reduce reliability
- Some organizations front GlobalProtect with access controls that shrink the reachable population
Force repeated service failure into maintenance mode
- The initial trigger works against the target build
- Attacker can repeat requests
- HA pairs, upstream filtering, and fast operator intervention limit duration
- The blast radius is normally one exposed portal/gateway or one firewall pair, not full tenant compromise
Disrupt remote access and edge enforcement
- Target device is in active production use
- Users or branch traffic depend on the affected GlobalProtect/firewall path
- If the affected node is standby, lab-only, or low-usage, impact is contained
- Good HA design and alternate access paths blunt business impact
The supporting signals.
| In-the-wild status | As of the Palo Alto advisory, the vendor says it is not aware of malicious exploitation. |
|---|---|
| KEV status | Not listed in the CISA Known Exploited Vulnerabilities catalog at time of review. |
| PoC availability | Palo Alto rates exploit maturity as POC. Secondary aggregators also report multiple public GitHub PoCs; treat that as plausible but less authoritative than the vendor advisory. |
| EPSS | Secondary-source snapshots place EPSS around 0.09% with roughly 9.7th percentile exposure likelihood. That is low, which fits a niche app-specific DoS rather than a mass-exploitation RCE. |
| CVSS interpretation | CVSS v3.1 7.5 HIGH is driven by AV:N/AC:L/PR:N/UI:N but only A:H impact. NVD also displays Palo Alto's CVSS v4 CVSS-BT 6.6 MEDIUM, reflecting a more tempered provider view. |
| Exposure gate | This issue is applicable only when a GlobalProtect gateway or portal is enabled. No enabled GlobalProtect, no exploit path. |
| Affected versions | PAN-OS 12.1, 11.2, 11.1, 10.2, and 10.1 have affected sub-ranges; Cloud NGFW is unaffected. Prisma Access 10.2/11.2 had fixes and Palo Alto says customer instances were already upgraded. |
| Fixed versions | Key fixed builds include 12.1.4, 11.2.10-h2, 11.2.7-h8, 11.2.4-h15, 11.1.13, 11.1.10-h9, 11.1.6-h23, 11.1.4-h27, 10.2.18-h1, 10.2.16-h6, 10.2.13-h18, 10.2.10-h31, 10.2.7-h32, and 10.1.14-h20. |
| Scanning / exposure data | There is no authoritative public count tied specifically to CVE-2026-0227 in the sources reviewed. Still, internet-facing GlobalProtect is a common enterprise pattern, and GreyNoise reported targeted fingerprinting of Palo Alto GlobalProtect/PAN-OS in October 2025, likely informed by public exposure data from services like Shodan/Censys; that is contextual exposure intel, not CVE-specific exploitation evidence. |
| Disclosure / reporting | Disclosed 2026-01-15 via Palo Alto; the vendor credits an external reporter but does not name them. |
noisgate verdict.
The decisive amplifier is that this is unauthenticated traffic against a commonly internet-exposed remote-access surface. The decisive limiter is that the impact is availability-only and gated behind enabled GlobalProtect, which keeps it out of CRITICAL despite the ugly operational failure mode.
Why this verdict
- Baseline stays elevated: vendor starts at 7.5 HIGH because the bug is network-reachable, unauthenticated, and low-complexity against a perimeter service.
- Exposure narrows the population: the attack only works where GlobalProtect portal or gateway is enabled, so this is not a blanket PAN-OS bug across every firewall.
- Post-compromise is not required: this is still pre-auth from the internet, which stops me from downgrading it into routine hygiene territory.
- Modern controls only partially help: MFA and endpoint posture do nothing against a pre-auth crash path; only exposure reduction, upstream filtering, and HA materially reduce risk.
- Blast radius is operational, not existential: the attacker can knock over remote access and possibly the firewall role on that device, but there is no code execution, credential theft, or tenant-wide takeover in the advisory.
- Threat evidence is muted: no KEV listing and no vendor-confirmed malicious exploitation mean there is less upward pressure than you would see for an active edge zero-day.
Why not higher?
This is not CRITICAL because there is no evidence here of code execution, auth bypass into access, data theft, or integrity compromise. The bug also requires a specific exposed feature state, and its effect is usually bounded to outage of the affected firewall or HA pair rather than domain-wide compromise.
Why not lower?
This is not MEDIUM because the attacker does not need credentials, user interaction, or an internal foothold. On a public GlobalProtect deployment, this is a direct internet-to-outage path on a security control that many organizations depend on for workforce access.
What to do — in priority order.
- Restrict GlobalProtect exposure — Apply source-IP allowlists, geo/IP restrictions, or trusted-network scoping in front of exposed GlobalProtect portals and gateways wherever business-possible; for a HIGH verdict, deploy this within 30 days. This directly attacks the biggest amplifier in the chain: anonymous internet reachability.
- Enable upstream rate controls — Use DDoS protections, reverse-proxy throttling where supported, or edge ACL/rate-limit controls to reduce the attacker's ability to repeatedly re-trigger the failure condition; deploy within 30 days. This will not fix the bug, but it raises attacker friction and can turn a reliable crash loop into noisy failed probing.
- Fail over cleanly — Validate HA health, session synchronization, and monitoring for maintenance-mode transitions on any internet-facing GlobalProtect pair within 30 days. If you cannot prevent the trigger, you want the service interruption contained and obvious.
- Remove unused GlobalProtect roles — Disable portal or gateway functions on firewalls that do not actively serve remote users, and do it within 30 days. Because the bug is feature-gated, reducing enabled footprint immediately shrinks the affected population.
- Alert on service instability — Create NOC/SOC alerts for GlobalProtect process restarts, tunnel drops, maintenance-mode entry, and sudden declines in active remote-user sessions within 30 days. This shortens mean time to detect and gives operators a fighting chance before a nuisance DoS becomes a business outage.
- MFA does not help because the crash path is pre-auth.
- Endpoint posture checks do not help because the attacker never needs to enroll a client.
- Generic EDR is mostly irrelevant on the firewall appliance; this is a network-service availability issue, not a host malware problem.
- Waiting for a threat signature alone is weak coverage because app-specific crash conditions often do not map cleanly to stable IPS patterns.
Crowdsourced verification payload.
Run this from an auditor workstation that can reach the firewall's management or API interface over HTTPS. Invoke it as python3 check_cve_2026_0227.py --host fw01.example.com --api-key YOURKEY using a PAN-OS XML API key with permission to run operational commands and read config; no shell access on the firewall is required.
#!/usr/bin/env python3
# Check exposure to CVE-2026-0227 on a PAN-OS firewall via XML API.
# Usage: python3 check_cve_2026_0227.py --host fw01.example.com --api-key <KEY>
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
import argparse
import ssl
import sys
import urllib.parse
import urllib.request
import xml.etree.ElementTree as ET
TIMEOUT = 20
def die(status, msg, code):
print(status)
if msg:
print(msg)
sys.exit(code)
def api_get(host, params):
qs = urllib.parse.urlencode(params, safe='<>/=@[]\"\' ')
url = f"https://{host}/api/?{qs}"
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
req = urllib.request.Request(url, headers={"User-Agent": "noisgate-cve-2026-0227-checker/1.0"})
with urllib.request.urlopen(req, context=ctx, timeout=TIMEOUT) as resp:
return resp.read()
def get_xml_root(data):
root = ET.fromstring(data)
if root.get('status') == 'error':
line = ''.join(root.itertext()).strip()
raise RuntimeError(f"API error: {line}")
return root
def parse_version(v):
# Examples: 11.2.7-h4, 11.1.13, 10.2.18-h1
v = v.strip()
hotfix = 0
if '-h' in v:
base, h = v.split('-h', 1)
try:
hotfix = int(h)
except ValueError:
hotfix = 0
else:
base = v
parts = base.split('.')
if len(parts) != 3:
raise ValueError(f"Unrecognized PAN-OS version: {v}")
return tuple(int(x) for x in parts) + (hotfix,)
def cmp_ver(a, b):
return (a > b) - (a < b)
def in_range(v, lo, hi=None):
pv = parse_version(v)
plo = parse_version(lo)
if cmp_ver(pv, plo) < 0:
return False
if hi is None:
return True
phi = parse_version(hi)
return cmp_ver(pv, phi) <= 0
def is_vulnerable_version(v):
# Palo Alto advisory branch logic.
if in_range(v, '12.1.2', '12.1.3-h2'):
return True
if in_range(v, '11.2.0', '11.2.4-h14'):
return True
if in_range(v, '11.2.5', '11.2.7-h7'):
return True
if in_range(v, '11.2.8', '11.2.10-h1'):
return True
if in_range(v, '11.1.0', '11.1.4-h26'):
return True
if in_range(v, '11.1.5', '11.1.6-h22'):
return True
if in_range(v, '11.1.7', '11.1.10-h8'):
return True
if in_range(v, '11.1.11', '11.1.12'):
return True
if in_range(v, '10.2.0', '10.2.7-h31'):
return True
if in_range(v, '10.2.8', '10.2.10-h30'):
return True
if in_range(v, '10.2.11', '10.2.13-h17'):
return True
if in_range(v, '10.2.14', '10.2.16-h5'):
return True
if in_range(v, '10.2.17', '10.2.18'):
return True
if in_range(v, '10.1.0', '10.1.14-h19'):
return True
return False
def get_version(host, api_key):
data = api_get(host, {
'type': 'op',
'cmd': '<show><system><info></info></system></show>',
'key': api_key,
})
root = get_xml_root(data)
node = root.find('.//sw-version')
if node is None or not (node.text and node.text.strip()):
raise RuntimeError('Could not read sw-version from API response')
return node.text.strip()
def get_device_config(host, api_key):
xpaths = [
"/config/devices/entry[@name='localhost.localdomain']",
"/config/shared",
]
texts = []
for xp in xpaths:
try:
data = api_get(host, {
'type': 'config',
'action': 'show',
'xpath': xp,
'key': api_key,
})
root = get_xml_root(data)
texts.append(ET.tostring(root, encoding='unicode'))
except Exception:
pass
if not texts:
raise RuntimeError('Could not retrieve configuration subtree(s)')
return '\n'.join(texts)
def gp_present(config_xml):
tags = ['global-protect-gateway', 'global-protect-portal', 'global-protect']
low = config_xml.lower()
return any(t in low for t in tags)
def main():
ap = argparse.ArgumentParser(description='Check CVE-2026-0227 exposure on PAN-OS')
ap.add_argument('--host', required=True, help='Firewall hostname or IP')
ap.add_argument('--api-key', required=True, help='PAN-OS XML API key')
args = ap.parse_args()
try:
version = get_version(args.host, args.api_key)
except Exception as e:
die('UNKNOWN', f'Failed to query PAN-OS version: {e}', 2)
try:
config_xml = get_device_config(args.host, args.api_key)
has_gp = gp_present(config_xml)
except Exception as e:
# We can still make a version-only judgment, but config gating matters.
if is_vulnerable_version(version):
die('UNKNOWN', f'Version {version} is in an affected range, but GlobalProtect exposure could not be verified: {e}', 2)
die('PATCHED', f'PAN-OS version {version} is outside vendor-affected ranges.', 0)
if not is_vulnerable_version(version):
die('PATCHED', f'PAN-OS version {version} is outside vendor-affected ranges. GlobalProtect present={has_gp}.', 0)
if has_gp:
die('VULNERABLE', f'PAN-OS version {version} is in an affected range and GlobalProtect configuration was detected.', 1)
die('PATCHED', f'PAN-OS version {version} is in an affected range, but no GlobalProtect configuration was detected in the retrieved config. Validate manually if this device is Panorama-managed.', 0)
if __name__ == '__main__':
main()
If you remember one thing.
Sources
- Palo Alto advisory for CVE-2026-0227
- NVD entry for CVE-2026-0227
- CISA Known Exploited Vulnerabilities catalog
- PAN-OS XML API overview
- Palo Alto docs: Explore the XML API
- GreyNoise reporting on targeted scanning of Palo Alto GlobalProtect/PAN-OS
- Wiz CVE page with EPSS snapshot
- SentinelOne CVE page with EPSS probability snapshot
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.