Apprise URLs: schemes that act on the server itself, such as syslog://, are accepted from any account #12

Closed
opened 2026-10-01 10:48:13 +00:00 by tiagoagueda · 1 comment
Owner

Found on 2026-09-29 in a read-only review of postulo-apprise at 7637d899d, reading which schemes build() accepts and how Apprise 1.13.1 implements the ones that have no remote party.

build() accepts every URL that apprise.Apprise().add() accepts. Apprise also ships services that deliver to the machine it runs on: syslog:// wherever Python's syslog module imports, which is every Linux install, and the desktop ones (dbus, kde, qt, glib, gnome, macosx, windows) when their libraries are present. A connection is one person's setting; these write to something that belongs to the operator.

  • Where: src/postulo_apprise/notifier.py:59-71 (build) has no list of schemes, allowed or refused. src/postulo_apprise/notifier.py:96-99 (names_a_server) answers no for these, because their templates declare no host token, so destination_of returns None and nothing further is asked. In Apprise, plugins/syslog.py:28 imports syslog at module level, the class does not override enabled, its only token is facility, and its send calls syslog.syslog(...) with the notification's title and body; the logperror option adds LOG_PERROR, which copies each message to the process's standard error.
  • What happens: on a Linux host, an account saves a syslog:// line, optionally naming a facility such as auth or daemon. Every notification for that account is then written to the host's system log under that facility, tagged Apprise[pid]. With the standard-error option it is also written into Postulo's own log stream, in a container as much as on a bare host. The text is the notification's title and body: reminder text the account holder wrote, or text taken from a captured page. Where there is no log socket and the option is off, as in the container image, the line does nothing and Test still reports "Delivered to 1 service."
  • Who can trigger it: any signed-in account on an instance that has this plugin installed and runs on Linux. No staff rights are needed.
  • Why it matters: log injection. An account holder can place text of their choosing beside real entries in the operator's system log, under a facility that monitoring may treat as authoritative, and in the application log that the operator reads to investigate incidents. It is also a notifier that reports success while reaching nobody.
  • Fix: refuse schemes that have no remote party. A small deny-list checked in _problems (syslog, dbus, kde, qt, glib, gnome, macosx, windows) is the minimum; an allow-list of reviewed schemes would cover it and any local service Apprise adds later. Compare against server.secure_protocol and server.protocol as well as the typed scheme, since Apprise accepts aliases. Refuse at the form with a translated sentence naming the line, and again before sending, as the destination check already does.

This was read, not run: the review machine is Windows, where syslog does not import and Apprise rejects the scheme. The desktop classes are registered there and report enabled = False for lack of their libraries.

Done when

  • A test in tests/test_apprise.py asserts that validate() refuses a syslog:// line with the new sentence, and that send() raises ConfigurationError for a stored one. On Linux it fails today; make it independent of the platform by testing the refusal against the scheme rather than against what Apprise happens to load.
Found on 2026-09-29 in a read-only review of postulo-apprise at 7637d899d, reading which schemes `build()` accepts and how Apprise 1.13.1 implements the ones that have no remote party. `build()` accepts every URL that `apprise.Apprise().add()` accepts. Apprise also ships services that deliver to the machine it runs on: `syslog://` wherever Python's `syslog` module imports, which is every Linux install, and the desktop ones (`dbus`, `kde`, `qt`, `glib`, `gnome`, `macosx`, `windows`) when their libraries are present. A connection is one person's setting; these write to something that belongs to the operator. - **Where:** `src/postulo_apprise/notifier.py:59-71` (`build`) has no list of schemes, allowed or refused. `src/postulo_apprise/notifier.py:96-99` (`names_a_server`) answers no for these, because their templates declare no `host` token, so `destination_of` returns `None` and nothing further is asked. In Apprise, `plugins/syslog.py:28` imports `syslog` at module level, the class does not override `enabled`, its only token is `facility`, and its `send` calls `syslog.syslog(...)` with the notification's title and body; the `logperror` option adds `LOG_PERROR`, which copies each message to the process's standard error. - **What happens:** on a Linux host, an account saves a `syslog://` line, optionally naming a facility such as `auth` or `daemon`. Every notification for that account is then written to the host's system log under that facility, tagged `Apprise[pid]`. With the standard-error option it is also written into Postulo's own log stream, in a container as much as on a bare host. The text is the notification's title and body: reminder text the account holder wrote, or text taken from a captured page. Where there is no log socket and the option is off, as in the container image, the line does nothing and *Test* still reports "Delivered to 1 service." - **Who can trigger it:** any signed-in account on an instance that has this plugin installed and runs on Linux. No staff rights are needed. - **Why it matters:** log injection. An account holder can place text of their choosing beside real entries in the operator's system log, under a facility that monitoring may treat as authoritative, and in the application log that the operator reads to investigate incidents. It is also a notifier that reports success while reaching nobody. - **Fix:** refuse schemes that have no remote party. A small deny-list checked in `_problems` (`syslog`, `dbus`, `kde`, `qt`, `glib`, `gnome`, `macosx`, `windows`) is the minimum; an allow-list of reviewed schemes would cover it and any local service Apprise adds later. Compare against `server.secure_protocol` and `server.protocol` as well as the typed scheme, since Apprise accepts aliases. Refuse at the form with a translated sentence naming the line, and again before sending, as the destination check already does. This was read, not run: the review machine is Windows, where `syslog` does not import and Apprise rejects the scheme. The desktop classes are registered there and report `enabled = False` for lack of their libraries. ## Done when - A test in `tests/test_apprise.py` asserts that `validate()` refuses a `syslog://` line with the new sentence, and that `send()` raises `ConfigurationError` for a stored one. On Linux it fails today; make it independent of the platform by testing the refusal against the scheme rather than against what Apprise happens to load.
tiagoagueda added this to the 0.5.0 milestone 2026-10-01 10:48:13 +00:00
Author
Owner

Fixed by pull request #23.

Fixed by pull request #23.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo-apprise#12
No description provided.