A hotel front desk that lets you request the same room key ten thousand times per phone call
libsoup is GNOME's HTTP client/server library. This bug lives in the server-side implementation of HTTP Range requests: a client can stuff a single request with a huge number of overlapping byte ranges, and the server dutifully allocates memory for each one. Result is temporary memory ballooning, not a hard crash. Affected are libsoup 2.x and libsoup3 branches prior to the April 2025 upstream fixes (Red Hat backports landed in RHSA-2025:4439 / RHSA-2025:4508 / RHSA-2025:8128; Debian tracked via bug 1103264).
Vendor score of 5.3 MEDIUM is technically defensible via the CVSS math (AV:N/AC:L/PR:N/UI:N, A:L), but it wildly overstates the operational risk. libsoup in enterprise fleets is overwhelmingly loaded as an HTTP *client* by GNOME desktop applications (Evolution, gnome-online-accounts, Epiphany). The *server* API is used by a small population — mostly Rygel/DLNA media servers, GNOME development test harnesses, and a few embedded appliances. Real-world exposure is minimal.
3 steps from start to impact.
Locate a libsoup-based HTTP server
soup_server_* APIs to serve HTTP — not a client that merely links libsoup. Typical candidates are Rygel (DLNA/UPnP media sharing), some GNOME test/demo servers, or bespoke embedded appliances. Fingerprinting is via Server: header quirks or protocol behavior.- Reachable TCP port hosting a libsoup-server-based HTTP endpoint
- Endpoint that honors
Rangerequests (i.e. serves static or byte-addressable content)
- Enterprise Linux fleets rarely run libsoup as a server; the server API is a niche use case
- Corporate perimeters do not expose DLNA/Rygel — that's a home-LAN protocol
- Most web-facing HTTP in enterprises is nginx/Apache/HAProxy/IIS/envoy, none of which use libsoup
libsoup, libsoup3), not by whether the server API is actually in use — expect false-positive noise on every GNOME workstation.Send a crafted Range request
curl invocation with a Range: bytes=0-1,0-1,0-1,… header containing thousands of overlapping ranges. No public exploit repo needed — one line of shell. The server allocates a buffer per range.- Network path to the port
- Endpoint returns a resource that supports partial content (200/206 with
Accept-Ranges: bytes)
- Any reverse proxy in front (nginx, HAProxy, Cloudflare) will normalize or reject absurd
Rangeheaders before they hit the origin - Request-size limits on load balancers cap the payload
Memory pressure on the host
- Attacker sustains request volume
- Target has no cgroup/systemd memory limit
- systemd unit
MemoryMax=or container cgroup limits contain the blast - OOM killer restarts the service, self-healing
- No RCE, no data disclosure, no integrity impact
Range headers with hundreds of overlapping ranges. Configure client_header_buffer_size and a WAF rule (ModSecurity CRS 920200) to reject Range headers with more than ~10 entries. No mitigation SLA — LOW severity means this rides in the normal 365-day remediation window unless you have a Rygel/DLNA appliance publicly reachable.MemoryMax=512M (or lower per role) on the systemd unit, or a container --memory limit. Bounds the blast so a memory-thrash request kills the process cleanly and lets systemd restart it, instead of pressuring the whole host.lsof -p <pid> | grep libsoup or ss -tlnp correlated against package-owner queries. Ignore the flood of client-only positives from workstations. Focus remediation on the real server population.dnf update / apt upgrade traffic. noisgate remediation SLA for LOW: no formal deadline, treat as backlog hygiene.- Blocking
Rangerequests entirely — breaks legitimate resume-download and video-seek behavior; overreacts to a low-severity bug. - EDR / AV signatures — this is a resource-consumption bug in a userland library, not a malware payload; no signature will fire.
- Network segmentation alone — if the vulnerable Rygel/DLNA service is on the segment with any untrusted user, they can still trigger it; segmentation helps but doesn't fix.
The supporting signals.
| In-the-wild exploitation | None observed. Not in CISA KEV. No campaigns tracked by Mandiant, CrowdStrike, or GreyNoise tags. |
|---|---|
| Public PoC | No dedicated exploit repo needed — reproducible with a one-line curl sending a bloated Range header. No Metasploit/Nuclei template as of assessment. |
| EPSS | 0.0057 (~0.57%) — bottom-half percentile; FIRST models don't expect exploitation. |
| CISA KEV | Not listed. |
| CVSS 3.1 vector | AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L → 5.3 MEDIUM. Availability-only, low impact; no C/I. |
| Affected versions | libsoup 2.x and libsoup3 prior to upstream patches merged April 2025. Check distro backports rather than raw upstream numbers. |
| Fixed / backported | RHEL 9: RHSA-2025:4439 & RHSA-2025:4508; RHEL 8: RHSA-2025:8128. Debian bookworm/trixie tracked via bug 1103264. Fedora 40/41 pushed updates April–May 2025. |
| Exposure telemetry | Shodan/Censys do not fingerprint libsoup server distinctly; realistic internet-exposed population is dominated by home Rygel/DLNA on residential IPs, near-zero in enterprise ASN space. |
| Disclosure | 2025-04-14, GNOME project via Red Hat Product Security coordination. |
| Impact ceiling | Memory bloat only. Red Hat notes explicitly: *not* a full DoS. No RCE, no info leak. |
Sources.
Why this verdict
- Server API is a niche use case: the vast majority of
libsoup-linked processes are GNOME desktop apps acting as HTTP clients; the vulnerablesoup_server_*code path never executes for them. - Impact ceiling is availability-low: Red Hat's own writeup states this is not a full DoS — memory grows during the request and is released after. No RCE, no data disclosure.
- Reverse-proxy termination is the norm: any libsoup server sitting behind nginx, HAProxy, or a cloud LB has the pathological
Rangeheader normalized or rejected upstream. - Role multiplier — desktop / media-share role: the chain succeeds on a Rygel DLNA host or a GNOME test harness; blast radius is *that single process crashing and being restarted by systemd*. No lateral movement, no privilege change.
- Role multiplier — high-value role:
libsoupis not canonically deployed as an identity provider, hypervisor, backup server, CA, kernel-mode agent, network edge appliance, or CI/CD runner. No fleet-scale outcome exists for this component. Floor does not apply. - EPSS 0.0057 + no KEV + no public campaigns: predictive and observed signals both point to non-event.
Why not higher?
MEDIUM would require realistic enterprise-server exposure. Between the vanishing installed base of libsoup-server processes, the availability-only impact, and trivial mitigation via any fronting proxy, there is no operational reason to prioritize this above LOW.
Why not lower?
Not IGNORE because there is a real, remotely reachable code defect with unauthenticated trigger; teams running Rygel, kiosk appliances, or bespoke libsoup-based services genuinely should patch it during normal maintenance windows. Documenting it as backlog hygiene rather than pretending it doesn't exist.
Crowdsourced verification payload.
Run on each Linux target as any user (root not required for rpm/dpkg queries). Invoke as ./check-cve-2025-32907.sh. Exits 0 PATCHED, 1 VULNERABLE, 2 UNKNOWN. Also flags whether the host is actually running a libsoup-server process — the only case that operationally matters.
#!/usr/bin/env bash
# check-cve-2025-32907.sh — libsoup Range-header memory DoS
set -u
VULN=0
UNKNOWN=0
FOUND_PKG=0
echo '== libsoup CVE-2025-32907 check =='
# --- Package version check -------------------------------------------------
if command -v rpm >/dev/null 2>&1; then
for pkg in libsoup libsoup3; do
ver=$(rpm -q --qf '%{VERSION}-%{RELEASE}\n' "$pkg" 2>/dev/null | grep -v 'not installed')
[ -z "$ver" ] && continue
FOUND_PKG=1
echo "[pkg] $pkg $ver"
# RHEL backport tags: el9_5, el9_6, el8_10 with post-April-2025 release strings
case "$ver" in
*el9_5*|*el9_6*|*el8_10*|*el10*)
# Trust distro backport tags
echo " -> distro backport tag present, assumed PATCHED" ;;
*)
echo " -> release tag not recognized as post-fix, marking VULNERABLE"
VULN=1 ;;
esac
done
elif command -v dpkg-query >/dev/null 2>&1; then
for pkg in libsoup2.4-1 libsoup-3.0-0; do
ver=$(dpkg-query -W -f='${Version}\n' "$pkg" 2>/dev/null)
[ -z "$ver" ] && continue
FOUND_PKG=1
echo "[pkg] $pkg $ver"
# Debian fixed: libsoup2.4 >= 2.74.3-3+deb12u1 ; libsoup3 >= 3.2.2-2+deb12u1 (approximate)
case "$pkg" in
libsoup2.4-1)
dpkg --compare-versions "$ver" ge '2.74.3-3+deb12u1' || { VULN=1; echo ' -> older than fix, VULNERABLE'; } ;;
libsoup-3.0-0)
dpkg --compare-versions "$ver" ge '3.2.2-2+deb12u1' || { VULN=1; echo ' -> older than fix, VULNERABLE'; } ;;
esac
done
else
echo '[warn] no rpm/dpkg — cannot verify package version'
UNKNOWN=1
fi
if [ $FOUND_PKG -eq 0 ]; then
echo '[info] libsoup not installed — NOT AFFECTED'
exit 0
fi
# --- Server-role check (the only case that actually matters) --------------
echo '== libsoup server-role check =='
SERVERS=0
if command -v lsof >/dev/null 2>&1; then
while read -r pid; do
[ -z "$pid" ] && continue
if lsof -p "$pid" 2>/dev/null | grep -q libsoup; then
# Listening sockets on this pid?
if ss -tlnp 2>/dev/null | grep -q "pid=$pid,"; then
cmd=$(ps -p "$pid" -o comm= 2>/dev/null)
echo " [!] pid=$pid ($cmd) linked to libsoup AND listening — HIGH-RELEVANCE target"
SERVERS=$((SERVERS+1))
fi
fi
done < <(pgrep -a . 2>/dev/null | awk '{print $1}')
fi
[ $SERVERS -eq 0 ] && echo ' no libsoup-linked listening processes found (client-only exposure)'
# --- Verdict ---------------------------------------------------------------
if [ $VULN -eq 1 ]; then
if [ $SERVERS -gt 0 ]; then
echo 'RESULT: VULNERABLE (and running as server — patch)'
else
echo 'RESULT: VULNERABLE (client-only linkage — low operational risk)'
fi
exit 1
fi
if [ $UNKNOWN -eq 1 ]; then echo 'RESULT: UNKNOWN'; exit 2; fi
echo 'RESULT: PATCHED'
exit 0