A booby-trapped help file that turns the GNOME helper into a quiet file-exfil drone
Yelp is the GNOME desktop's built-in help viewer. It renders Mallard XML .page documents, and the renderer happily honors XInclude directives plus inline SVG with JavaScript. An attacker who can convince a user to open a crafted ghelp:// URL or a .page file gets the helper to pull arbitrary local files (anything the user's UID can read — ~/.ssh/id_rsa, ~/.config, /etc/passwd) into the rendered DOM, then ship them off via embedded JS to an attacker-controlled endpoint. Affected: Yelp ≤ 42.1 and corresponding yelp-xsl ≤ 42.1, shipped by default on Ubuntu 22.04/24.04, Fedora, Debian, RHEL 9, openSUSE, and other GNOME-based distros. Fixed in Yelp 42.3 / yelp-xsl 42.3 (June 12, 2025); distros have backports (RHSA-2025:4505, Fedora FEDORA-2025-e788608959, USN updates).
Vendor labeled this HIGH (7.4) based on CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N — confidentiality high, scope changed, user interaction required. The label is *defensible* for a Linux desktop where ssh keys, GPG keyring, and cloud credential files sit in $HOME. But for an enterprise fleet, the population that matters is narrow: only Linux desktops/workstations with GNOME and Yelp installed, where a human clicks a .page payload. Most enterprise Linux is headless server, where Yelp isn't installed or invoked. Net: vendor severity overstates the *fleet* risk for a typical defender; for a developer-heavy Linux-desktop shop it's about right.
5 steps from start to impact.
Craft a malicious Mallard .page help file
<xi:include parse="text" href="file:///home/victim/.ssh/id_rsa"/> directive and an inline SVG with a <script> block. The PoC by parrot409 (GitHub gist) is the canonical weaponization. Payload is a single self-contained .page file.- Attacker has authoring capability for the target's help-file delivery vector
- Trivial — public PoC available
.page with embedded <script> are minimal; YARA rules would have to be hand-writtenDeliver via ghelp:// URI or attachment
.page file or wraps it in a ghelp:///help: URI delivered via phishing email, IM, or a malicious web page. On GNOME, clicking a ghelp:// link launches Yelp. Alternatively, the file is dropped to disk and a .desktop file or filemanager double-click invokes Yelp.- Target uses a GNOME desktop with default URI handlers
- Email/IM/browser delivers the link or attachment without stripping
- Most enterprise email gateways do not block
.pageorghelp://because they're obscure — this is friction *for the defender*, not the attacker - Modern browsers prompt before handing off custom schemes
ghelp://; you'll need a custom blockUser opens the help file
- User is logged into a GNOME session
- User opts to open the file
- Requires social engineering —
.pageis not a file type most users recognize as a help document, which paradoxically makes phishing pretexts harder
yelp spawning with a suspicious argvXInclude reads sensitive local files
yelp-xsl) honors the XInclude directive and pulls the target file's contents into the rendered output as text. There is no sandbox — the read happens with the user's UID. Any file readable by that UID is in scope: SSH keys, browser cookie DBs, kube configs, AWS creds, GPG keyrings.- Sensitive files exist in paths readable by the user
- AppArmor/SELinux confinement for yelp is not enforced (default on most distros)
- Ubuntu's stock AppArmor profile for yelp is *not* enforced
- On hardened distros (Qubes, Tails) the helper runs in a constrained context
EXECVE/PATH watch on ~/.ssh/id_* opened by yelp is a high-fidelity signalSVG JavaScript exfiltrates over HTTPS
<script> reads the now-included DOM text and POSTs it to an attacker server via fetch() or by setting img.src to a logging endpoint. WebKitGTK (Yelp's renderer) honors outbound network requests by default; there is no CSP applied to local Mallard content.- Outbound HTTPS from the workstation to attacker infra is permitted
- Egress-filtered networks with a default-deny proxy block the POST
- Zscaler/Netskope SWG with TLS inspection can flag the unusual outbound from
WebKitWebProcess
WebKitWebProcess (child of yelp) to an unknown destination is the cleanest IOCThe supporting signals.
| In-the-wild status | No confirmed campaigns. Not on CISA KEV. No exploitation telemetry from Mandiant, CrowdStrike, or Red Canary as of June 2026. |
|---|---|
| Proof-of-concept | Public PoC by parrot409 at gist.github.com/parrot409; writeup by Michael Catanzaro (GNOME/Red Hat) on the GNOME blog. |
| EPSS | 0.10598 (~10.6%) — elevated for a desktop bug but reflects PoC availability, not active exploitation |
| KEV | Not listed as of 2026-06-30 |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N — UI:R is the load-bearing constraint; no integrity/availability impact |
| Affected versions | Yelp ≤ 42.1 and yelp-xsl ≤ 42.1 on GNOME desktops (Ubuntu 22.04/24.04, Fedora 41/42, RHEL 9/10, Debian 12, openSUSE Leap/Tumbleweed) |
| Fixed versions | Yelp 42.3 / yelp-xsl 42.3 (upstream, 2025-06-12). Backports: RHEL 9 via RHSA-2025:4505, Fedora 42 FEDORA-2025-e788608959, Ubuntu USN, Debian DSA |
| Exposure data | Not externally scannable — Yelp is a desktop binary, not a network service. Shodan/Censys/GreyNoise data is not applicable. Use internal MDM/Intune/JAMF/SCCM/Ansible inventory. |
| Disclosed | 2025-04-03 (NVD); originally surfaced 2025-03-18; fix landed 2025-06-12 |
| Reporter | parrot409 (research credit); coordinated with GNOME security via Michael Catanzaro |
noisgate verdict.
Downgraded from HIGH to MEDIUM because the *single most decisive factor* is affected-population scope: Yelp ships only on GNOME-based Linux desktops and requires a user to click a .page or ghelp:// payload, so the at-risk fleet for a typical enterprise is the Linux-workstation subset, not servers. The blast radius is single-user file exfiltration with no code execution or lateral movement, which keeps it below the HIGH bucket despite the public PoC.
Why this verdict
- User interaction required (UI:R) — no zero-click vector. The chain dies at the inbox if your secure email gateway flags unknown attachments or your browser blocks custom-scheme handoff.
- Affected population is narrow — Yelp is a desktop-only package; headless Linux servers (the bulk of most enterprise Linux estates) don't install it. EPSS 0.106 reflects PoC presence, not active campaigns.
- Blast radius is single-user, single-host — confidentiality only, no integrity or availability impact, no code-execution primitive beyond reading what the user's UID already can. No privilege escalation, no persistence primitive included.
- Role multiplier: developer/SRE workstation — chain succeeds, blast radius is *significant* (SSH keys, kubeconfigs,
~/.aws/credentials, GPG signing keys → potential pivot to production). For shops where Linux devs hold prod credentials in$HOME, this floats to the top of the MEDIUM bucket. - Role multiplier: general office workstation (Linux) — chain succeeds, blast radius is the user's documents and browser cookies. Local nuisance, not a fleet event.
- Role multiplier: server / headless host — Yelp typically not installed; chain does not run. Zero impact for the dominant Linux deployment role.
- No KEV listing, no observed campaigns — 14 months post-disclosure with a public PoC and no exploitation telemetry argues against a crash patch cycle.
Why not higher?
HIGH would require either active exploitation (none), a wider attack surface (server-side or zero-click — neither applies), or a credible chain to code execution and lateral movement (this is read-only file exfil within one UID). For Linux-developer-heavy shops where stolen SSH/cloud keys mean prod compromise, treat this as the *top* of MEDIUM and accelerate, but it does not meet the HIGH floor.
Why not lower?
LOW is wrong because the file-read primitive trivially captures secrets-in-home-directory (~/.ssh, ~/.aws, ~/.kube) on developer hosts, and PoC weaponization is public. The role multiplier on a dev workstation is too high to relegate to backlog hygiene.
What to do — in priority order.
- Disable the
ghelp://andhelp:URI handlers on managed Linux desktops — Remove or override/usr/share/applications/yelp.desktop'sMimeTypeentries that register Yelp as the handler forx-scheme-handler/ghelpandx-scheme-handler/help, and unregister Yelp fromapplication/vnd.gnome.mallard+xml. Ship via Ansible/Puppet/Salt within the MEDIUM mitigation window — there is no formal SLA for MEDIUM, so align with your next desktop config push (target ≤ 30 days for the developer cohort). - Block
.pageattachments andghelp://URIs at the email gateway — Add.pageto the disallowed-attachment list in Proofpoint/Mimecast/Defender for O365, and have your SWG (Zscaler/Netskope/Cloudflare Gateway) refuse rewrites ofghelp:schemes. Roll out within the next mail-policy cycle. - Apply the distro backport immediately on developer/SRE workstations — RHEL:
dnf update yelp yelp-xsl(RHSA-2025:4505). Ubuntu/Debian:apt-get install --only-upgrade yelp yelp-xsl. Fedora:dnf update --advisory FEDORA-2025-e788608959. Prioritize hosts where users hold cloud or SSH credentials in$HOME. - Enforce AppArmor/SELinux confinement on
yelp— Ubuntu ships an unenforced AppArmor profile for yelp; set it toenforce(aa-enforce /etc/apparmor.d/usr.bin.yelp) and extend it to deny reads of~/.ssh/,~/.aws/,~/.kube/,~/.gnupg/. Reduces blast radius even if patch is missed. - Hunt for retroactive exploitation — auditd query: any
yelpprocess thatopen()ed files under~/.ssh,~/.aws,~/.kube, or~/.config/gcloudin the last 90 days. Pair with EDR network telemetry onWebKitWebProcesschild ofyelp.
- Network segmentation — Yelp runs locally on the user's workstation; the exfil is outbound HTTPS from a trusted host, not lateral traffic.
- Disabling JavaScript browser-wide — Yelp uses WebKitGTK as a library, not the browser; browser settings don't affect it.
- Removing Yelp entirely — packagers often pull it back in as a dependency of
gnome-control-centerorgnome-shell. Mark/hold instead, or replace the binary with a stub. - MFA on the workstation login — does nothing once the user is logged in and clicks the help file.
Crowdsourced verification payload.
Run on each Linux desktop/workstation as a non-root user (root not required to read package versions). Invoke as bash check-cve-2025-3155.sh; exits 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN/NOT_INSTALLED. Push via Ansible/Salt and aggregate exit codes.
#!/usr/bin/env bash
# noisgate verification: CVE-2025-3155 (Yelp arbitrary file read)
# Patched in upstream yelp 42.3 / yelp-xsl 42.3 (or distro-backported equivalents).
set -u
VULN=1; PATCHED=0; UNKNOWN=2
# Step 1: is Yelp even installed?
if ! command -v yelp >/dev/null 2>&1; then
# Could still be installed without being on PATH; check pkg DB
if ! (dpkg -s yelp >/dev/null 2>&1 || rpm -q yelp >/dev/null 2>&1); then
echo "NOT_INSTALLED (yelp absent — not vulnerable)"
exit $PATCHED
fi
fi
# Step 2: read installed version per package manager
get_ver() {
local pkg="$1"
if command -v dpkg-query >/dev/null 2>&1; then
dpkg-query -W -f='${Version}\n' "$pkg" 2>/dev/null | head -n1
elif command -v rpm >/dev/null 2>&1; then
rpm -q --qf '%{VERSION}-%{RELEASE}\n' "$pkg" 2>/dev/null | head -n1
fi
}
YELP_VER=$(get_ver yelp)
XSL_VER=$(get_ver yelp-xsl)
if [ -z "$YELP_VER" ] && [ -z "$XSL_VER" ]; then
echo "UNKNOWN (could not determine yelp / yelp-xsl version)"
exit $UNKNOWN
fi
# Step 3: compare. Upstream fix is 42.3. Distro backports advertise the same
# upstream version OR carry a patched suffix (e.g. RHEL: 42.1-2.el9_5).
# Strategy: if upstream >= 42.3, PATCHED. If upstream < 42.3, check for known
# backport release markers from RHEL/Ubuntu/Fedora advisories.
ver_ge() {
# returns 0 if $1 >= $2 (semver-ish)
[ "$(printf '%s\n%s\n' "$2" "$1" | sort -V | head -n1)" = "$2" ]
}
check_one() {
local name="$1" ver="$2"
[ -z "$ver" ] && return 0 # not installed, skip
local base=${ver%%-*}
if ver_ge "$base" "42.3"; then
echo " $name $ver -> upstream patched"
return 0
fi
# Backport detection: distro advisories
case "$ver" in
*el9_5*|*el9_6*|*el10*) echo " $name $ver -> RHEL backport (RHSA-2025:4505)"; return 0;;
*ubuntu*22.04*|*ubuntu*24.04*)
# Ubuntu USN-published versions carry +deb/ubuntu suffix; manual sub-check needed.
echo " $name $ver -> AMBIGUOUS Ubuntu version, verify against USN"; return 2;;
*fc42*|*fc41*) echo " $name $ver -> Fedora backport (FEDORA-2025-e788608959)"; return 0;;
esac
echo " $name $ver -> < 42.3 and no backport marker"
return 1
}
rc1=0; rc2=0
check_one yelp "$YELP_VER"; rc1=$?
check_one yelp-xsl "$XSL_VER"; rc2=$?
if [ $rc1 -eq 1 ] || [ $rc2 -eq 1 ]; then
echo "VULNERABLE (CVE-2025-3155): upgrade to yelp/yelp-xsl >= 42.3 or distro backport"
exit $VULN
fi
if [ $rc1 -eq 2 ] || [ $rc2 -eq 2 ]; then
echo "UNKNOWN: ambiguous version, cross-check against vendor advisory"
exit $UNKNOWN
fi
echo "PATCHED (CVE-2025-3155)"
exit $PATCHED
If you remember one thing.
yelp installed are out of scope). For that cohort, push the distro-backported yelp/yelp-xsl package (RHSA-2025:4505, FEDORA-2025-e788608959, USN, DSA) via your normal desktop update channel. Per the noisgate mitigation SLA for MEDIUM: there is no formal mitigation SLA — go straight to the noisgate remediation SLA of ≤ 365 days, but front-load the developer/SRE/SecOps cohort (cloud creds and SSH keys in $HOME) within 30 days because the role-multiplier on those hosts is real and the PoC is public. In parallel, block .page attachments at the email gateway and unregister Yelp from ghelp:///help: URI handlers on managed images. Do not crash-patch the server fleet for this — your time is better spent on the next KEV-listed issue.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.