This is a loaded trapdoor inside the machine room, not a hole in the front wall
CVE-2026-45250 is a FreeBSD kernel stack overflow in setcred(2): the kernel copies a user-controlled supplementary group list into a fixed-size stack buffer before enforcing the privilege check. That turns a syscall intended for privileged callers into a local privilege escalation path for unprivileged users. The affected supported branches called out by FreeBSD are releng/14.3, releng/14.4, releng/15.0, stable/14, and stable/15; the visible release exposure starts with FreeBSD 14.3, when setcred(2) first shipped.
The vendor's HIGH 7.8 is technically fair in a vacuum because successful exploitation ends in kernel-context code execution and root. In enterprise reality, though, the decisive friction is that the attacker must already have local code execution or a valid low-privilege account on the target host. That makes this a post-initial-access privilege escalator, not an initial entry bug, so it lands lower than a remotely reachable flaw even though the per-host impact is severe.
4 steps from start to impact.
Gain a low-privilege foothold on the FreeBSD host
- Affected FreeBSD host
- Ability to run local code or commands as a non-root user
- Host is in a supported affected branch or equivalent source build
- No network-only path; attacker must already be on the box
- Many enterprise FreeBSD systems are single-purpose appliances with limited interactive users
- MFA, PAM hardening, and reduced shell access can prevent reaching this stage
Trigger the overflow with the public venglin/setcred PoC
setcred(2) with an oversized supplementary group list so the kernel writes beyond a fixed stack buffer before checking whether the caller is allowed to use the syscall. That makes exploitation reachable from an unprivileged account despite the syscall's intended privilege gate.- Local execution as a non-root user
- Kernel includes vulnerable
setcred(2)implementation - Ability to make the syscall from userland
- Custom-seccomp-like syscall mediation, if present, could interfere
- Nonstandard hardened kernels or local policy frameworks may change exploit reliability
- Some environments tightly restrict user code execution on bastions and appliances
Pivot from overflow to controlled kernel execution
zfs.ko via ZSTD_initCStream_advanced. In practice, that means modern kernel protections do not save you if the host matches the tested configuration.- Exploit-compatible kernel layout
- Common modules and code paths present;
zfs.koloaded for the published modern-kernel chain - amd64 GENERIC-like environment for the demonstrated PoC
- Reliability may drop on unusual kernels, custom builds, or stripped-down deployments
- Hosts without the same module mix may require adaptation
- This is still per-host exploitation, not one-shot fleet-wide compromise
Exit as root and own the host
- Successful kernel control-flow hijack
- Target host stores secrets or has onward access worth abusing
- Blast radius is usually limited to the compromised host unless the box is a bastion, CI node, storage head, or shared shell server
- Least-privilege service design can limit what valuable material exists locally
- Relying on the fact that
setcred(2)is meant for privileged callers does not help, because the unsafe copy happens before the privilege check. - Disabling internet exposure alone does not fix this; the exploit path is local, so an attacker who lands through another route can still use it.
- Assuming kernel hardening like SMAP/SMEP will save you is unsafe; the public research specifically describes a chain that works with those protections enabled.
- Removing a few
setuidbinaries is not a real mitigation here; the published researcher notes there is no clean userland mitigation.
The supporting signals.
| In-the-wild status | No authoritative public evidence of active exploitation found in CISA KEV or vendor materials as of 2026-05-29. That lowers urgency versus internet-facing zero-days. |
|---|---|
| Public exploit / PoC | Yes. Public write-up by Przemyslaw Frasunek / FatGid and PoC source at github.com/venglin/setcred; the researcher states working LPE exploits were verified end-to-end on FreeBSD 14.4-RELEASE amd64. |
| EPSS | Prompt-supplied EPSS 0.00006 indicates very low expected near-term mass exploitation. Percentile was not supplied in the prompt and is not asserted here. |
| KEV status | Not listed in CISA's Known Exploited Vulnerabilities catalog. |
| CVSS vector | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H = easy once local, no user interaction, full host impact, but local-only reachability is the big real-world brake. |
| Affected versions | FreeBSD advisory says all supported versions at disclosure time; practically, the vulnerable syscall's visible release lifespan starts at 14.3. Supported affected branches explicitly listed: releng/14.3, releng/14.4, releng/15.0, stable/14, stable/15. |
| Fixed versions | Patched release branches include 14.3-RELEASE-p14, 14.4-RELEASE-p5, and 15.0-RELEASE-p9. Source-built users need the advisory patch or a tree at/after the cited commit revisions. |
| Workaround availability | None per FreeBSD advisory. The researcher also notes there is no clean userland mitigation for unpatched systems. |
| Exposure / scanning reality | This bug is not remotely scannable as a network exploit; exposure depends on who can run code locally. A secondary industry write-up cites roughly 1,062 discoverable FreeBSD instances on Shodan, but that number matters less than whether those systems grant shell, CI, jail, or tenant access. |
| Disclosure and credits | FreeBSD advisory was announced on 2026-05-20; NVD published on 2026-05-21. Credits include Ryan of Calif.io and Przemyslaw Frasunek. |
Sources.
Why this verdict
- Requires local code execution first:
AV:L/PR:Lmeans the attacker already has a shell, job, or code-exec foothold on the host. That is post-initial-access friction and deserves a meaningful drop from the vendor's 7.8 baseline. - Reachable population is narrower than CVSS implies: this is FreeBSD-only, and the vulnerable syscall first appeared in the 14.3 era. Most enterprise estates have a much smaller FreeBSD footprint than Linux or Windows, reducing aggregate risk.
- Exploit quality keeps it out of LOW: there is a public write-up, public PoC, no user interaction, no workaround, and demonstrated root on modern amd64 builds including a path that survives SMAP/SMEP.
Why not higher?
It is not a front-door vulnerability. There is no unauthenticated remote path, no lateral spread mechanic, and no evidence of active exploitation strong enough to override the attacker-position friction. In a 10,000-host program, post-compromise LPEs do not outrank remotely reachable perimeter bugs.
Why not lower?
Once an attacker has a local foothold, this looks dangerously usable: low complexity, no user interaction, public exploit material, and kernel-context impact. That matters on shared-shell servers, CI workers, bastions, storage/admin nodes, and any FreeBSD system where multiple users or workloads land.
Crowdsourced verification payload.
Run this on each target FreeBSD host as a normal user; root is not required. Save it as check-cve-2026-45250.sh and run sh check-cve-2026-45250.sh. It checks release builds by freebsd-version and returns UNKNOWN for custom/source-built -STABLE trees where advisory commit-level validation is needed.
#!/bin/sh
# check-cve-2026-45250.sh
# Detect likely exposure to CVE-2026-45250 on FreeBSD release builds.
# Outputs: VULNERABLE / PATCHED / UNKNOWN
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u
if ! command -v freebsd-version >/dev/null 2>&1; then
echo "UNKNOWN: freebsd-version not found"
exit 2
fi
KV=$(freebsd-version -k 2>/dev/null || true)
UV=$(freebsd-version -u 2>/dev/null || true)
V="${KV:-$UV}"
if [ -z "$V" ]; then
V="$UV"
fi
if [ -z "$V" ]; then
echo "UNKNOWN: unable to determine FreeBSD version"
exit 2
fi
case "$V" in
*-STABLE*|*-CURRENT*)
echo "UNKNOWN: STABLE/CURRENT source trees require commit-level validation against FreeBSD-SA-26:18.setcred"
exit 2
;;
esac
# Extract major.minor and patch level from strings like:
# 14.3-RELEASE-p13
# 14.4-RELEASE-p5
# 15.0-RELEASE
BASE=$(printf '%s' "$V" | sed -E 's/^([0-9]+\.[0-9]+).*/\1/')
PATCH=$(printf '%s' "$V" | sed -nE 's/.*-p([0-9]+).*/\1/p')
if [ -z "$BASE" ]; then
echo "UNKNOWN: could not parse version string: $V"
exit 2
fi
if [ -z "$PATCH" ]; then
PATCH=0
fi
case "$BASE" in
14.3)
if [ "$PATCH" -ge 14 ]; then
echo "PATCHED: $V (fixed in 14.3-RELEASE-p14 or later)"
exit 0
else
echo "VULNERABLE: $V (needs 14.3-RELEASE-p14 or later)"
exit 1
fi
;;
14.4)
if [ "$PATCH" -ge 5 ]; then
echo "PATCHED: $V (fixed in 14.4-RELEASE-p5 or later)"
exit 0
else
echo "VULNERABLE: $V (needs 14.4-RELEASE-p5 or later)"
exit 1
fi
;;
15.0)
if [ "$PATCH" -ge 9 ]; then
echo "PATCHED: $V (fixed in 15.0-RELEASE-p9 or later)"
exit 0
else
echo "VULNERABLE: $V (needs 15.0-RELEASE-p9 or later)"
exit 1
fi
;;
*)
echo "UNKNOWN: $V is outside the directly validated release patterns; check the advisory and source branch state"
exit 2
;;
esac