This is a janitor’s key that only opens one side door in one building layout
CVE-2026-4948 is a local firewalld mis-authorization flaw in the D-Bus setters setZoneSettings2 and setPolicySettings. In vulnerable builds, those setters are protected with PK_ACTION_CONFIG_INFO instead of PK_ACTION_CONFIG, which matters because the shipped desktop polkit profile allows configuration *inspection* without authentication. Upstream, the bug affects firewalld <= 2.4.0; the fix lands in v2.4.1. Debian shows backported fixes in 0.9.3-2+deb11u1 for bullseye and 2.3.1-1+deb13u1 for trixie, while SUSE ships fixed package builds such as firewalld >= 1.3.4-150600.13.6.1 on SLES 15 SP6/SP7.
The vendor’s MEDIUM 5.5 rating is technically fair in a lab, but it is too generous for enterprise patch triage. Real-world exploitation requires local unprivileged code execution or shell access first, then a host that actually uses the desktop policy profile, and the outcome is runtime firewall-state tampering on that one host, not remote takeover. That is classic post-initial-access friction, so this gets downgraded to LOW.
4 steps from start to impact.
Land on the box first
- Local unprivileged access to the Linux host
- firewalld installed and running
- This is post-compromise by definition
- Many enterprise Linux systems are headless servers, not interactive multi-user desktops
Find a host with the desktop polkit profile
config.info-style operations without authentication. The upstream fix changes the setters to require PK_ACTION_CONFIG, closing the gap.- A vulnerable firewalld build
- Desktop polkit policy installed/active for Firewalld
- Server-oriented deployments typically do not rely on the desktop policy path
- Backported distro fixes mean package version alone may mislead
Call the mis-authorized D-Bus methods
busctl, gdbus, or a small Python D-Bus client, the attacker invokes setZoneSettings2 or setPolicySettings. Because those setters were wrongly guarded with the weaker auth action, firewalld accepts runtime policy changes that should have required admin authentication.- Access to the system bus
- Knowledge of firewalld D-Bus method signatures
- The attacker still needs working local execution and D-Bus access
- The bug changes runtime state, so the impact is immediate but not necessarily persistent
busctl/gdbus access to org.fedoraproject.FirewallD1; off-the-shelf scanners rarely validate this path.Punch a temporary hole in host filtering
- A useful firewall rule change exists for the attacker’s objective
- Target workload depends on firewalld for host-level filtering
- Impact is bounded to the affected host
- Runtime-only changes may disappear on reload/restart or be overwritten by config management
firewall-cmd --list-all-zones and --runtime-to-permanent drift, review journald firewalld events, and alert on unexpected runtime policy churn.config.info is not enough to reach sensitive runtime setters. For LOW, there is no SLA — treat as backlog hygiene and bundle this into desktop hardening baselines.firewall-cmd, busctl, gdbus, and direct D-Bus access to org.fedoraproject.FirewallD1, then compare runtime vs permanent rules. For LOW, there is no SLA — treat as backlog hygiene, but it is a useful detective control on admin workstations and shared Linux hosts.- A perimeter WAF or external IPS does nothing here because there is no direct network-reachable exploit surface.
- Blind package-version reporting does not reliably tell you exploitable state because distro backports and the desktop-policy prerequisite both matter.
- MFA does not stop the vulnerable D-Bus method once the attacker already has local code execution under a normal user context.
The supporting signals.
| In-the-wild status | No known active exploitation in primary sources reviewed. OpenCVE surfaces CISA ADP enrichment marking Exploitation: none; the user-provided KEV status is also No. |
|---|---|
| Proof-of-concept availability | No standalone exploit repo found in primary-source review. The public fix commit is enough for a competent operator to build a trivial busctl/gdbus abuse once local access exists. |
| EPSS | 0.00027 from the supplied intel — effectively near-zero exploit probability in fleet terms. Third-party mirrors place it around ~0.02% and roughly ~P5 percentile, but treat the percentile as low-confidence. |
| KEV status | Not KEV-listed. No CISA Known Exploited Vulnerabilities entry was found for this CVE in the reviewed catalog sources. |
| CVSS meaning | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N means local, low-complexity, low-privilege, no user interaction, with integrity impact only. That already tells you this is post-foothold. |
| Affected versions | Primary-source tracking says upstream firewalld <= 2.4.0 is affected. Red Hat CNA data explicitly marks RHEL 7 affected and leaves RHEL 8/9/10 and OpenShift 4 as unknown in the CNA record rather than broadly declaring them vulnerable. |
| Fixed versions | Upstream fix is firewalld v2.4.1. Debian lists fixed builds in bullseye 0.9.3-2+deb11u1, trixie 2.3.1-1+deb13u1, and unstable 2.4.0-2; SUSE lists fixed packages including firewalld >= 1.3.4-150600.13.6.1 on SLES 15 SP6/SP7. |
| Exposure population | Not internet-scannable in any meaningful way. This is a local D-Bus/polkit authorization flaw, so Shodan/Censys/FOFA style exposure counts do not map to attacker reachability. |
| Disclosure | Publicly disclosed 2026-03-27. NVD shows publication on 2026-03-27 and last modification on 2026-05-15. |
| Reporter | Reported by Asim Viladi Oglu Manizada per the CNA record exposed through OpenCVE. |
Sources.
Why this verdict
- Downward adjustment: requires local unprivileged access first — this is not an initial-access bug, not a perimeter bug, and not something an unauthenticated remote attacker can hit.
- Downward adjustment: desktop policy prerequisite narrows the blast radius — the exploitable path depends on the shipped desktop polkit profile being present/active, which is not how most headless Linux servers are run.
- Downward adjustment: impact is host-local and runtime-scoped — the attacker can tamper with the running firewall state on one machine, but this is not code execution and not an immediate fleet-wide persistence mechanism.
Why not higher?
If this were remotely reachable, unauthenticated, or broadly exposed across server fleets, the integrity impact to firewall policy would justify a much higher rating. But the chain is gated by local access first and then by a specific desktop authorization profile, which strips away most of the theoretical severity.
Why not lower?
It is still a real authorization flaw in a security control, not bookkeeping noise. On shared Linux workstations, developer boxes, VDI-style Linux desktops, or jump hosts where firewalld meaningfully segments traffic, an unprivileged user can weaken host filtering immediately and aid lateral movement.
Crowdsourced verification payload.
Run this on the target Linux host, not from a scanner workstation. Save it as check-cve-2026-4948.sh and execute sudo bash check-cve-2026-4948.sh; root is preferred so the script can inspect installed firewalld Python sources and polkit action files without path/permission surprises.
#!/usr/bin/env bash
# check-cve-2026-4948.sh
# Detects likely exploitable state for CVE-2026-4948.
# Exit codes:
# 0 = PATCHED
# 1 = VULNERABLE
# 2 = UNKNOWN
set -u
status="UNKNOWN"
reason=""
find_firewalld_py() {
local candidates=(
/usr/lib*/python*/site-packages/firewall/server/firewalld.py
/usr/lib*/python*/dist-packages/firewall/server/firewalld.py
/usr/lib/firewalld/firewalld.py
)
local f
for pattern in "${candidates[@]}"; do
for f in $pattern; do
[ -f "$f" ] && { echo "$f"; return 0; }
done
done
return 1
}
has_vuln_decorator() {
local file="$1"
python3 - "$file" <<'PY'
import sys
path = sys.argv[1]
with open(path, 'r', encoding='utf-8', errors='ignore') as fh:
lines = fh.readlines()
def prev_nonempty(idx):
j = idx - 1
while j >= 0:
s = lines[j].strip()
if s:
return s
j -= 1
return ""
z = False
p = False
for i, line in enumerate(lines):
s = line.strip()
if s.startswith('def setZoneSettings2('):
z = 'PK_ACTION_CONFIG_INFO' in prev_nonempty(i)
if s.startswith('def setPolicySettings('):
p = 'PK_ACTION_CONFIG_INFO' in prev_nonempty(i)
if z and p:
print('VULN')
sys.exit(0)
else:
print('PATCHED_OR_UNKNOWN')
sys.exit(1)
PY
}
has_desktop_policy() {
local dir file
for dir in /usr/share/polkit-1/actions /etc/polkit-1/actions; do
[ -d "$dir" ] || continue
while IFS= read -r -d '' file; do
if grep -q 'org.fedoraproject.FirewallD1.config.info' "$file" 2>/dev/null && \
grep -q 'org.fedoraproject.FirewallD1.policies.info' "$file" 2>/dev/null && \
grep -q '<allow_active>yes</allow_active>' "$file" 2>/dev/null; then
echo "$file"
return 0
fi
done < <(find "$dir" -maxdepth 1 -type f -name '*FirewallD*.policy' -print0 2>/dev/null)
done
return 1
}
firewalld_py="$(find_firewalld_py 2>/dev/null || true)"
if [ -z "$firewalld_py" ]; then
echo "UNKNOWN - could not locate installed firewalld Python service file"
exit 2
fi
if has_vuln_decorator "$firewalld_py" >/dev/null 2>&1; then
desktop_policy="$(has_desktop_policy 2>/dev/null || true)"
if [ -n "$desktop_policy" ]; then
echo "VULNERABLE - vulnerable setters found in $firewalld_py and desktop polkit policy present at $desktop_policy"
exit 1
else
echo "UNKNOWN - vulnerable setters found in $firewalld_py but no desktop polkit policy detected; prerequisite may be absent"
exit 2
fi
else
echo "PATCHED - vulnerable setter decorators not detected in $firewalld_py"
exit 0
fi