This is a control panel behind glass that forgot to stop other websites from putting their own buttons over it
CVE-2026-38978 is a clickjacking / UI-redress weakness in Transmission's browser-facing management surface. Upstream issue and fix data show the affected path is the HTTP response handling for the bundled WebUI and RPC endpoints, where Transmission through 4.1.1 did not add X-Frame-Options or CSP frame-ancestors protections before returning content. The public report also demonstrated the same missing headers on a 4.2.0-dev build before the March 31, 2026 fix, so the vulnerable behavior was not limited to one packaging flavor.
In practice this is less severe than a generic 'network attack' label would imply. The attacker does not get code execution, data exfiltration, or direct server compromise from the missing headers alone; they need a victim to load an attacker page and click through a precisely aligned hidden frame. Transmission's defaults also add meaningful friction: rpc_whitelist_enabled is true and the default whitelist is 127.0.0.1, which kills many remote-path scenarios unless admins deliberately broaden exposure or publish the UI through a reverse proxy.
4 steps from start to impact.
Host a lure page with a framed Transmission UI
iframe pointed at /transmission/web/ or /transmission/rpc, then CSS overlays or decoy buttons to steer clicks. No memory corruption or protocol bug is needed; the weakness is simply that vulnerable builds return frameable responses. The public GitHub issue includes reproducible header checks showing those protections were absent before the fix.- Attacker can get the victim to browse to an attacker-controlled page
- Victim browser can reach the Transmission WebUI/RPC endpoint, either on localhost, LAN, or a published URL
- If the UI is not reachable from the browser, the chain dies immediately
- Precise UI alignment is brittle across browsers, screen sizes, and future UI changes
/transmission/web/ and /transmission/rpc; network scanners looking for RCE patterns will miss it.Rely on reachable admin surface and surviving access controls
rpc_enabled is true for transmission-daemon, rpc_bind_address defaults to 0.0.0.0, but rpc_whitelist_enabled is also true and rpc_whitelist defaults to 127.0.0.1. That means the realistic sweet spot is often browser-to-localhost or deliberately exposed/reverse-proxied deployments, not generic internet spray-and-pray exploitation.- Target runs
transmission-daemonwith WebUI/RPC active - Whitelist/auth/reverse-proxy settings allow the victim browser to reach the interface
- Default IP whitelist sharply reduces true remote exposure
- Many enterprise environments do not run Transmission at all, shrinking population
settings.json for rpc_whitelist_enabled, rpc_whitelist, rpc_authentication_required, and any non-localhost publishing.Steer victim clicks into privileged actions
- Victim interacts with the lure page
- Victim is already authenticated, or the deployment does not require authentication from the victim's reachable path
- User interaction is mandatory
- Same-origin policy still blocks easy response reading; this is action-steering, not broad data theft
Impact stays inside the Transmission management plane
- Victim actions successfully trigger meaningful WebUI operations
- No direct privilege escalation beyond the Transmission process context
- Follow-on host compromise would require a separate bug or dangerous local scripting configuration
The supporting signals.
| In-the-wild status | No evidence of active exploitation found in reviewed authoritative sources, and no CISA KEV listing as of 2026-06-05. |
|---|---|
| Proof-of-concept availability | Public reproduction exists via GitHub issue #8726, including curl header checks and runtime evidence. I found no turnkey exploit kit or mass-exploitation tooling. |
| EPSS | 0.00017 from the user-provided intel. That is extremely low exploit-likelihood signaling; reviewed sources did not provide a trustworthy percentile for this CVE. |
| KEV status | Not listed in the CISA KEV catalog. Disclosure date provided in the case file is 2026-06-02. |
| Weakness class | CWE-1021 — Improper Restriction of Rendered UI Layers or Frames, i.e. clickjacking / UI redress. |
| Affected versions | Transmission through 4.1.1 is affected per the CVE text. The public bug report also reproduced the missing headers on 4.2.0-dev before the fix landed on 2026-03-31. |
| Fixed version | Upstream 4.1.2 adds X-Frame-Options: SAMEORIGIN and Content-Security-Policy: frame-ancestors 'self' in the HTTP response path. I found no authoritative distro backport bulletin for this specific CVE during this review. |
| Exposure reality | Defaults cut the reachable population down hard: docs show rpc_enabled=true for daemon, but also rpc_whitelist_enabled=true with default whitelist 127.0.0.1. Translation: many remote attacks fail by default, though browser-to-localhost and intentionally published reverse-proxy deployments remain in play. |
| Scanning / exposure data | Transmission's WebUI commonly uses TCP/9091. Public internet search engines like Shodan and Censys can query this surface, but I did not pull a defensible internet-wide count from an authoritative source for this assessment. |
| Reporter / fix provenance | Bug reported by quart27219 on GitHub on 2026-03-24; fix merged by ckerr on 2026-03-31 and shipped in 4.1.2. |
noisgate verdict.
The decisive downward pressure is attack-chain friction: this bug generally needs a reachable WebUI, a live victim in a browser, and successful click steering on a framed admin interface. It is a legitimate privilege-bearing web weakness, but the reachable population and blast radius are both much narrower than classic internet-facing application bugs.
Why this verdict
- First assessment only: there is no vendor or authority CVSS baseline, so this is a fresh severity call rather than an upgrade or downgrade.
- Remote reachability is narrower than it looks: although daemon docs show
rpc_bind_addressdefaulting to0.0.0.0, the defaultrpc_whitelist_enabled=trueandrpc_whitelist=127.0.0.1mean many deployments are not broadly reachable from arbitrary remote hosts. - Exploit requires a live victim and user interaction: attacker success depends on getting a user to browse a malicious page and click through a hidden frame. That is materially weaker than unauthenticated server-side exploitation.
- Blast radius is mostly application-scoped: the likely outcome is unauthorized torrent or configuration operations inside Transmission, not direct host takeover, credential dumping, or broad data theft.
Why not higher?
This is not a no-click, no-auth, server-side compromise. The chain needs browser reachability plus user interaction, and Transmission's default whitelist sharply limits true remote exposure in many installations. Even when successful, the direct impact is typically bounded to the Transmission control plane.
Why not lower?
This is still a privileged admin UI missing a basic browser-side safety boundary, and the weakness is publicly reproducible. For systems where users browse the Web from the same machine that can reach the daemon—especially localhost or reverse-proxied NAS setups—an attacker can turn ordinary user clicks into unauthorized administrative actions.
What to do — in priority order.
- Add anti-framing headers at the reverse proxy — If you front Transmission with Nginx, Apache, Traefik, or a NAS proxy, inject
X-Frame-Options: SAMEORIGINand CSPframe-ancestors 'self'immediately. For a MEDIUM verdict there is no noisgate mitigation SLA — go straight to the 365-day remediation window, but exposed instances should still get this hardening on the next admin change window because it directly kills the exploit path. - Keep the WebUI local-only — Preserve or restore the default local trust boundary: leave
rpc_whitelist_enabledon, keeprpc_whitelistnarrow, and do not publish port9091externally unless there is a business case. There is no mitigation SLA for MEDIUM, so treat this as hardening work folded into normal admin maintenance while you plan the upgrade within 365 days. - Require authentication everywhere the UI is reachable — Turn on
rpc_authentication_requiredanywhere the WebUI is reachable beyond localhost. Authentication does not solve clickjacking by itself, but it removes the easiest unauthenticated local/LAN cases and is worthwhile defense-in-depth while you complete patching in the 365-day remediation window. - Disable the WebUI if nobody needs it — If your use case is CLI-only or API-free, remove the entire browser attack surface by disabling RPC/WebUI on those nodes. Again, no mitigation SLA for MEDIUM; use ordinary service review and cleanup cycles, then finish patching or retirement within 365 days.
SameSitecookie tuning is not the main answer here, because Transmission often uses Basic auth and the OWASP guidance explicitly notes clickjacking can survive controls that only target cookie inclusion.- A generic WAF is weak value here; the browser is loading legitimate application pages, not sending obviously malicious payloads.
- Relying on obscure URLs or a non-default port does not help. If the browser can reach the UI, a framed lure page can still target it.
Crowdsourced verification payload.
Run this from an auditor workstation or the target host against the live WebUI/RPC endpoint. Invoke it as bash check-cve-2026-38978.sh http://127.0.0.1:9091 or bash check-cve-2026-38978.sh https://transmission.example.com; it needs only network access to the UI and curl, with no elevated privileges required.
#!/usr/bin/env bash
# check-cve-2026-38978.sh
# Detects whether a Transmission WebUI/RPC endpoint appears vulnerable to CVE-2026-38978.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u
BASE_URL="${1:-http://127.0.0.1:9091}"
BASE_URL="${BASE_URL%/}"
WEB_URL="${BASE_URL}/transmission/web/"
RPC_URL="${BASE_URL}/transmission/rpc"
need_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "UNKNOWN: required command not found: $1"
exit 2
}
}
need_cmd curl
need_cmd awk
need_cmd sed
need_cmd grep
fetch_headers() {
local url="$1"
curl -ksS -D - -o /dev/null --max-time 10 "$url" 2>/dev/null
}
has_clickjack_protection() {
local headers="$1"
echo "$headers" | tr -d '\r' | grep -Eiq '^X-Frame-Options:[[:space:]]*SAMEORIGIN$|^X-Frame-Options:[[:space:]]*DENY$' && return 0
echo "$headers" | tr -d '\r' | grep -Eiq '^Content-Security-Policy:.*frame-ancestors[[:space:]]+('\''self'\''|none)' && return 0
return 1
}
extract_version() {
local v=""
if command -v transmission-daemon >/dev/null 2>&1; then
v=$(transmission-daemon --version 2>/dev/null | sed -nE 's/.* ([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' | head -n1)
fi
if [ -z "$v" ] && command -v transmission-qt >/dev/null 2>&1; then
v=$(transmission-qt --version 2>/dev/null | sed -nE 's/.* ([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' | head -n1)
fi
if [ -z "$v" ] && command -v transmission-cli >/dev/null 2>&1; then
v=$(transmission-cli --version 2>/dev/null | sed -nE 's/.* ([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' | head -n1)
fi
echo "$v"
}
verlte() {
[ "$1" = "$2" ] && return 0
[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" = "$1" ]
}
WEB_HEADERS=$(fetch_headers "$WEB_URL")
RPC_HEADERS=$(fetch_headers "$RPC_URL")
VERSION=$(extract_version)
WEB_OK=1
RPC_OK=1
has_clickjack_protection "$WEB_HEADERS" && WEB_OK=0
has_clickjack_protection "$RPC_HEADERS" && RPC_OK=0
if [ $WEB_OK -eq 0 ] || [ $RPC_OK -eq 0 ]; then
echo "PATCHED"
echo "detail: anti-framing headers detected on at least one Transmission HTTP response path"
[ -n "$VERSION" ] && echo "version: $VERSION"
exit 0
fi
if [ -n "$VERSION" ] && verlte "$VERSION" "4.1.1"; then
echo "VULNERABLE"
echo "detail: local Transmission version is $VERSION (<= 4.1.1) and no anti-framing headers were detected"
exit 1
fi
if [ -n "$WEB_HEADERS$RPC_HEADERS" ]; then
echo "VULNERABLE"
echo "detail: endpoint responded but anti-framing headers were not detected on /transmission/web/ or /transmission/rpc"
[ -n "$VERSION" ] && echo "version: $VERSION"
exit 1
fi
echo "UNKNOWN"
echo "detail: could not retrieve headers and no local Transmission version was detected"
exit 2
If you remember one thing.
Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.