← Back to Feed CACHED · 2026-06-30 15:02:46 · CACHE_KEY CVE-2025-13601
CVE-2025-13601 · CWE-190 · Disclosed 2025-11-26

A heap-based buffer overflow problem was found in glib through an incorrect calculation of buffer size in…

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

A length-math bug deep inside glib's URI escaper that only matters if you can already feed it gigabyte-scale strings locally

When g_escape_uri_string() walks a candidate string and counts how many bytes the percent-encoded output will need, the running total can wrap a 32-bit size_t on platforms where the worst-case expansion (×3 per byte) of a sufficiently large input overflows the allocation size calculation. The allocator then returns a buffer smaller than the encoder thinks it asked for, and the encoder writes past the end. This affects glib (glib2) before 2.86.3, with distro backports landing as 2.66.8-1+deb11u7 (Bullseye), 2.74.6-2+deb12u8 (Bookworm), 2.84.4-3~deb13u2 (Trixie), and the upstream fix in 2.86.3-1. The flaw lives in GNOME GitLab issue #3827.

Vendor severity is HIGH (7.7) under AV:L/AC:L/PR:N/UI:N/C:N/I:H/A:H — local, no privileges, integrity + availability impact. The score is technically defensible because corruption of a heap chunk can hand an attacker code execution in the calling process, but in practice nearly every real caller of g_escape_uri_string() (GIO, GVfs, desktop URI handling, GNotification, GApplication) is invoked with attacker-controllable strings that are kilobytes, not the hundreds-of-megabytes required to wrap the length math. The realistic severity sits in MEDIUM territory: it is a latent corruption primitive looking for a caller that will hand it a giant string, and very few do.

"Local-only integer overflow in a rarely-reached glib URI helper. Vendor's 7.7 is generous; patch in the normal cycle."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Reach a glib caller with attacker-influenced URI input

The attacker needs a process linked against vulnerable glib that exposes a code path eventually invoking g_escape_uri_string() (or g_uri_escape_string() / g_uri_escape_bytes() which share the helper). Typical surfaces are GVfs URI handlers, GNotification action URIs, desktop file Exec=/URL= parsing, and applications that build URIs from filenames or metadata. The input must be locally delivered — opening a file, mounting a share, clicking a .desktop shim, or passing a CLI argument.
Conditions required:
  • Local code execution as some user already present
  • A glib-linked desktop or service process that escapes attacker-supplied content
Where this breaks in practice:
  • Server fleets generally do not run glib URI escaping on tainted, unbounded input
  • Headless Linux servers ship glib but rarely link callers that escape user-shaped URIs
Detection/coverage: Standard SCA (Trivy, Grype, Snyk, OSV-Scanner, Qualys, Tenable plugin 276961) detects vulnerable glib2 by package version cleanly.
STEP 02

Deliver a string large enough to overflow the length calculation

The integer overflow only triggers when the count of bytes that need percent-escaping multiplied by 3 (worst case %XX) exceeds the type used for the allocation length. In practice that means hundreds of megabytes to gigabytes of input on 32-bit size_t paths, or astronomically large inputs on 64-bit. The attacker must find a caller that does not pre-bound input length.
Conditions required:
  • A caller that passes unbounded-length strings to the escaper
  • Enough memory to materialize the malicious string in the victim process
Where this breaks in practice:
  • Most desktop callers cap URIs at OS PATH limits or a few KB
  • GLib's own URI parsers enforce sanity limits before reaching the escaper in most paths
  • On 64-bit Linux (the dominant target) wrapping requires ~6 GB of input — implausible in benign flows and noisy in malicious ones
Detection/coverage: Memory-pressure anomalies in EDR; ASan/UBSan in dev builds catches it instantly.
STEP 03

Shape heap layout to land the overflow on something useful

A short overwrite past a freshly allocated buffer is not automatic RCE — modern allocators (glibc tcache, scudo, jemalloc) randomize adjacency, and the overflow size is bounded by how much the length math missed by. The attacker needs heap grooming primitives in the same process to place a useful target (a function pointer, vtable, or another length field) immediately after the under-sized allocation.
Conditions required:
  • A heap grooming primitive in the same process
  • Knowledge of allocator layout
Where this breaks in practice:
  • glibc 2.32+ tcache hardening, safe-linking, and pointer mangling raise the bar
  • ASLR + PIE on every modern distro break naive offsets
  • The corrupting bytes are themselves URI-escape characters — limited control of overwrite content
Detection/coverage: EDR with heap-corruption telemetry (CrowdStrike, Defender, SentinelOne) may catch the SIGSEGV; not a high-fidelity signal.
STEP 04

Convert corruption into code execution in caller's context

If steps 1–3 succeed, the attacker gains arbitrary code execution as the user running the glib caller — typically the logged-in desktop user, not root. There is no automatic privilege escalation; this is a user-context primitive that an attacker who is *already a local user* turns into… the same user they already were. The exception is a setuid/setgid binary or a system daemon (rare for URI-escaping callers).
Conditions required:
  • Heap grooming succeeded
  • Target process not sandboxed by snap/flatpak/AppArmor confinement
Where this breaks in practice:
  • Most glib URI consumers run as the unprivileged user the attacker already controls
  • Flatpak/snap sandboxing contains the blast radius
  • No known setuid caller of g_escape_uri_string() with attacker-controlled length
Detection/coverage: Post-exploit indicators (child process spawn, syscall anomalies) via EDR — generic, not CVE-specific.
03 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNone observed. No public campaign, no honeypot hits, not on CISA KEV.
Public PoCNo weaponized PoC published. GNOME GitLab issue #3827 describes the math bug; reproducers are conceptual (feed multi-GB string).
EPSS0.00306 (~0.3%) — well below the 1% triage threshold.
CISA KEVNot listed as of 2026-06-30.
CVSS vectorCVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:HAV:L is the dominant friction: no network reach, attacker must already be local.
Affected versionsglib < 2.86.3 upstream. Distro vulnerable ranges: Debian 11 < 2.66.8-1+deb11u7, Debian 12 < 2.74.6-2+deb12u8, RHEL 8 < glib2-2.56.4-168.el8_10, Amazon Linux per ALAS, IBM Netezza Appliance affected.
Fixed versionsUpstream 2.86.3; Debian backports 2.66.8-1+deb11u7 / 2.74.6-2+deb12u8 / 2.84.4-3~deb13u2; RHEL glib2-2.56.4-168.el8_10 (RHSA-2026:0975); Mageia MGASA-2026-0023; MIRACLE LINUX advisory issued.
Scanner exposureTenable plugin 276961, VulDB 333600, EUVD-2025-199720, OSV/GHSA pickup pending. No internet-facing surface for GreyNoise/Shodan/Censys to instrument.
Disclosure2025-11-26, via GNOME GitLab issue #3827, tracked Debian bug #1121488.
ReporterReported upstream to GNOME glib maintainers; no public researcher attribution in advisories.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to MEDIUM (4.8/10)

Downgraded one bucket because the AV:L attack vector requires the attacker already to be on the host, and the integer-overflow trigger requires multi-gigabyte input that no realistic glib URI caller will hand the function. Blast radius is limited to the caller's user context — there is no setuid amplifier and no high-value-role variant of this bug.

HIGH Patch identification and affected version ranges
HIGH Local-only attack vector and exploitation difficulty
MEDIUM Whether any niche caller passes unbounded URI input

Why this verdict

  • AV:L kills network reach. The vendor's own vector confirms no remote path; the attacker must already be on the box, which collapses to a privilege-escalation primitive at best.
  • No setuid / high-value-role caller. g_escape_uri_string() is invoked from desktop URI plumbing (GVfs, GIO, GNotification), GApplication, and userland apps — none of these are canonically high-value roles (no DC, hypervisor, IdP, PAM, backup, kernel agent runs URI escaping on attacker input). Role multiplier does not apply.
  • Role multiplier — server fleet: glib is present on virtually every Linux server but the vulnerable function is rarely on the data path for server workloads (web servers, databases, K8s nodes don't escape attacker URIs through this helper). Chain does not succeed in the high-value role.
  • Trigger size is implausible. Wrapping the length math on 64-bit requires ~6 GB of attacker-shaped input in a single allocation — instantly OOM-killed or detected by EDR on real fleets.
  • EPSS 0.3% + no KEV + no PoC — there is no observed adversary interest and no weaponization to chase.

Why not higher?

HIGH would require either a remote vector (this is AV:L), a high-value-role caller (none documented), or a credible exploitation chain. The integer overflow exists but the triggering caller does not exist in the high-blast-radius components defenders care about.

Why not lower?

LOW would imply no realistic impact, but the bug IS a memory-corruption primitive in a near-ubiquitous library. If a future caller emerges that hands it large attacker-controlled input — or a 32-bit embedded build is found — the calculus changes. MEDIUM keeps it on the 365-day remediation clock rather than ignored.

05 · Compensating Control

What to do — in priority order.

  1. Patch glib2 via vendor channel in next monthly window — RHEL: dnf upgrade glib2 to ≥ glib2-2.56.4-168.el8_10 (RHSA-2026:0975). Debian/Ubuntu: apt upgrade libglib2.0-0 to the per-release fixed version. Container base images: rebuild from updated upstream. No mitigation SLA at MEDIUM — fold into the noisgate remediation SLA of ≤ 365 days, but realistically ride the next maintenance window.
  2. Inventory which processes actually link vulnerable glib AND escape untrusted URIs — Run lsof | grep libglib-2.0 on representative hosts and cross-reference against your application inventory. Most servers will show glib loaded by systemd, NetworkManager, polkitd — none of which feed attacker-controlled multi-GB strings to the escaper. Use the result to deprioritize hosts where the caller is not exposed.
  3. Tighten desktop/Flatpak sandboxing where applicable — On user workstations, ensure Flatpak/snap confinement is enforced (flatpak override --reset) so a successful exploit stays inside the application sandbox rather than reaching the user's home dir. Useful as defense-in-depth, not a mitigation per se.
  4. Add memory-allocation anomaly alerting for desktop processes — Trigger telemetry when GUI processes attempt single allocations > 1 GB or hit OOM-kill — the only realistic trigger path produces conspicuous memory pressure that a tuned EDR or auditd rule will surface.
What doesn't work
  • WAF / network filtering — vulnerability is AV:L; no network packets traverse the vulnerable code.
  • Disabling URI handlers in browsers — the bug is in glib's escaper, not in URL parsing; browsers ship their own URL libraries.
  • Running as non-root — the bug already executes in user context; root is not the bar.
06 · Verification

Crowdsourced verification payload.

Run on each Linux target host as any user (no privileges required). Example: bash check-cve-2025-13601.sh. Detects vulnerable glib2 package version across RHEL/Debian/Ubuntu/Amazon Linux families and prints VULNERABLE / PATCHED / UNKNOWN.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# CVE-2025-13601 — glib g_escape_uri_string integer overflow
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u

verdict() { echo "$1"; exit "$2"; }

ver_ge() {
  # returns 0 if $1 >= $2 using dpkg/rpm semantics where available
  if command -v dpkg >/dev/null 2>&1; then
    dpkg --compare-versions "$1" ge "$2"
    return $?
  elif command -v rpmdev-vercmp >/dev/null 2>&1; then
    rpmdev-vercmp "$1" "$2" >/dev/null 2>&1
    [ $? -eq 11 ] && return 1 || return 0
  else
    # crude fallback
    [ "$(printf '%s\n%s\n' "$2" "$1" | sort -V | head -1)" = "$2" ] && return 0 || return 1
  fi
}

if command -v rpm >/dev/null 2>&1; then
  PKG=$(rpm -q --qf '%{VERSION}-%{RELEASE}\n' glib2 2>/dev/null | head -1)
  [ -z "$PKG" ] && verdict "UNKNOWN: glib2 not installed via rpm" 2
  # RHEL 8 fix: 2.56.4-168.el8_10
  if echo "$PKG" | grep -q 'el8'; then
    ver_ge "$PKG" "2.56.4-168.el8_10" && verdict "PATCHED: glib2-$PKG" 0
    verdict "VULNERABLE: glib2-$PKG (need >= 2.56.4-168.el8_10)" 1
  fi
  # Generic: anything upstream >= 2.86.3 is fixed
  UPSTREAM=$(echo "$PKG" | cut -d- -f1)
  ver_ge "$UPSTREAM" "2.86.3" && verdict "PATCHED: glib2-$PKG" 0
  verdict "VULNERABLE: glib2-$PKG (need backport or >= 2.86.3 upstream)" 1
fi

if command -v dpkg >/dev/null 2>&1; then
  PKG=$(dpkg-query -W -f='${Version}\n' libglib2.0-0 libglib2.0-0t64 2>/dev/null | head -1)
  [ -z "$PKG" ] && verdict "UNKNOWN: libglib2.0-0 not installed" 2
  CODENAME=$( ( . /etc/os-release; echo "$VERSION_CODENAME" ) 2>/dev/null )
  case "$CODENAME" in
    bullseye) FIX="2.66.8-1+deb11u7" ;;
    bookworm) FIX="2.74.6-2+deb12u8" ;;
    trixie)   FIX="2.84.4-3~deb13u2" ;;
    *)        FIX="2.86.3" ;;
  esac
  ver_ge "$PKG" "$FIX" && verdict "PATCHED: libglib2.0-0 $PKG (>= $FIX)" 0
  verdict "VULNERABLE: libglib2.0-0 $PKG (need >= $FIX)" 1
fi

verdict "UNKNOWN: no supported package manager detected" 2
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning: do not interrupt your sprint. This is a MEDIUM with no mitigation SLA — go straight to the noisgate remediation SLA of ≤ 365 days and slot the glib2 update into your next scheduled patch window (most fleets will pick it up in the next 30-day cycle anyway via routine dnf / apt updates). The noisgate mitigation SLA does not apply at MEDIUM; the AV:L vector, 6-GB-input trigger, EPSS 0.3%, and absence of KEV or PoC make this an opportunistic-patch case, not a fire drill. Use this week to confirm your SCA scanners (Trivy / Tenable plugin 276961 / OSV-Scanner) are flagging vulnerable glib2 across your image base so you do not inherit it via stale container layers.

Sources

  1. Debian Security Tracker — CVE-2025-13601
  2. Debian bug #1121488 — glib#3827 / CVE-2025-13601
  3. VulDB 333600 — CVE-2025-13601
  4. Red Hat RHSA-2026:0975 — glib2 security update
  5. Amazon Linux ALAS — CVE-2025-13601
  6. IBM Security Bulletin — glib2 affects Netezza Appliance
  7. Mageia MGASA-2026-0023 — glib2.0 update
  8. MIRACLE LINUX — glib2-2.56.4-168.el8_10
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.