The reference notifier can append to any file on the server; teach exact host matching and surface-only imports #1

Closed
opened 2026-09-15 21:23:45 +00:00 by tiagoagueda · 0 comments
Owner

postulo-helloworld is the plugin people are told to copy, so what it does wrong gets copied too. Found in the 2026-09-15 audit of the plugin repositories.

1. The notifier appends to any path a person types

  • src/postulo_helloworld/notifier.py:77-82: Path(config["path"]).expanduser().open("a").
  • Any account on an instance that installs this can append lines to any file the Postulo process can write, such as ~/.bashrc or ~/.ssh/authorized_keys.
  • The lines carry text that can come from a captured stranger's page (posting titles).

Fix: write only inside a directory the operator sets (an environment variable, defaulting to a subdirectory of the data volume), refuse paths that escape it, or simply use logging. Explain why in a comment, since this is the example others copy.

2. Host matching by substring

source.py:83: any(host in url for host in HOSTS), so https://evil.test/?hello.example matches.

Fix: compare urlsplit(url).hostname exactly (or as a suffix match on a dot boundary), with a test.

3. It teaches imports past the surface

notifier.py:24 and source.py:25 import postulo.plugins.base. Everything used (FieldSpec, TestResult, JobPostingData, declares, Manifest) is already on postulo.plugins.api. Switch now, and add the surface AST check to CI.

4. CI and version pin

  • .forgejo/workflows/ci.yml:39,41 runs scripts/compile_messages.py, which the repository does not have.
  • __version__ is 0.1.0 against 0.3.0 in pyproject.toml.

Fix: use the postulo-messages compile command and version from importlib.metadata.

`postulo-helloworld` is the plugin people are told to copy, so what it does wrong gets copied too. Found in the 2026-09-15 audit of the plugin repositories. ## 1. The notifier appends to any path a person types - `src/postulo_helloworld/notifier.py:77-82`: `Path(config["path"]).expanduser().open("a")`. - Any account on an instance that installs this can append lines to any file the Postulo process can write, such as `~/.bashrc` or `~/.ssh/authorized_keys`. - The lines carry text that can come from a captured stranger's page (posting titles). **Fix:** write only inside a directory the operator sets (an environment variable, defaulting to a subdirectory of the data volume), refuse paths that escape it, or simply use `logging`. Explain why in a comment, since this is the example others copy. ## 2. Host matching by substring `source.py:83`: `any(host in url for host in HOSTS)`, so `https://evil.test/?hello.example` matches. **Fix:** compare `urlsplit(url).hostname` exactly (or as a suffix match on a dot boundary), with a test. ## 3. It teaches imports past the surface `notifier.py:24` and `source.py:25` import `postulo.plugins.base`. Everything used (`FieldSpec`, `TestResult`, `JobPostingData`, `declares`, `Manifest`) is already on `postulo.plugins.api`. Switch now, and add the surface AST check to CI. ## 4. CI and version pin - `.forgejo/workflows/ci.yml:39,41` runs `scripts/compile_messages.py`, which the repository does not have. - `__version__` is `0.1.0` against `0.3.0` in `pyproject.toml`. **Fix:** use the `postulo-messages` compile command and version from `importlib.metadata`.
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-helloworld#1
No description provided.