SEC2-048: postulo-dav locks pyjwt 2.13.0, urllib3 2.7.0 and django 6.1.1, carrying 22 published advisories, and CI never audits the lock #31

Closed
opened 2026-10-17 10:39:29 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-10-16 in a read-only security review of postulo-dav at 1d49d6e, checked by a second, independent pass.

Severity: Low · Category: Dependencies · Reference: CWE-1104 (Use of Unmaintained Third Party Components); OWASP A06:2021 (Vulnerable and Outdated Components)

Location:

  • uv.lock (pyjwt 2.13.0, urllib3 2.7.0, oauthlib 3.3.1, django 6.1.1, django-allauth 65.19.2)
  • pyproject.toml:51 (postulo @ git+...@925e3e9cd35a97617cc45b36ecdde862d04515b1)
  • .forgejo/workflows/ci.yml:47-48,55 and .forgejo/workflows/release.yml:39-40 (curl -LsSf https://astral.sh/uv/install.sh | sh; uv sync --locked; no audit step)

Issue

A pip-audit 2.10.1 run on 2026-10-16 against the exported lock reports pyjwt 2.13.0 with fourteen advisories (PYSEC-2026-4140 to -4152 and -4183; fixed in 2.14.0 / 2.15.0, including HMAC key-handling flaws that allow token forgery and a JWKS redirect-following issue), urllib3 2.7.0 with three (PYSEC-2026-4175 to -4177, fixed in 2.8.0) and oauthlib 3.3.1 with one (CVE-2026-49265, fixed in 4.0.0). The lock also holds django 6.1.1, whose four security fixes in 6.1.2 pip-audit cannot see (postulo/postulo SEC2-044), and django-allauth 65.19.2, behind the releases that move to oauthlib 4. That is 14 + 3 + 1 + 4 = 22 advisories.

The plugin pins the core at 925e3e9cd (2026-10-10, five days and 210 commits behind the core's 56fc9d531). The pin is not the cause: the core's lock does not constrain a plugin's lock (only pyproject.toml floors do), and the plugin's own uv.lock has simply never been re-resolved.

The plugin's own code uses httpx through the guarded client (pyproject.toml:23) and imports neither jwt, requests nor urllib3, so these packages are reached only through django-allauth's OpenID Connect sign-in in the plugin's test environment. In production a plugin is installed into the core's environment under the core's constraint file (docker/Dockerfile, /app/constraints.txt), so the core's versions win; this lock describes what the plugin's tests run against and what a developer installs. Hence Low. Nothing would tell anybody: neither workflow runs pip-audit, and both install uv from the unversioned install.sh (the core pinned it with a checksum in postulo/postulo#790).

Impact

A developer or a CI run of this repository works in an environment with a JWT library that accepts forged tokens under some HMAC configurations and an HTTP stack with open advisories. If a future release of the plugin ever ships its lock (a standalone image, a uv tool install), the stale pins ship with it.

Fix

Re-resolve the lock: uv lock --upgrade (or --upgrade-package for pyjwt, urllib3, django, django-allauth and oauthlib); upgrading allauth brings oauthlib 4 with it, so the lock comes out clean. Re-pinning the core to its current main is worth doing at the same time but moves nothing on its own. Add to ci.yml the core's audit step (uv export --no-emit-project ... | pip-audit --strict) and the pinned installer (UV_VERSION, UV_INSTALLER_SHA256). Done when: pip-audit against the exported lock reports nothing and the CI workflow fails on a new advisory.

postulo/postulo-apprise#13 (open) - names this repository's unversioned installer line and missing audit step among "the other five Python plugin repositories", so the CI half is already filed there; the stale lock itself is not. #2 (closed) - "CI, pins and surface imports" of 2026-09-15, about the CI and the core pin, not the lock's advisories. postulo/postulo SEC2-044 and SEC2-045 - the Django and django-allauth lag in the core.

Found on 2026-10-16 in a read-only security review of `postulo-dav` at `1d49d6e`, checked by a second, independent pass. **Severity:** Low · **Category:** Dependencies · **Reference:** CWE-1104 (Use of Unmaintained Third Party Components); OWASP A06:2021 (Vulnerable and Outdated Components) **Location:** - `uv.lock` (`pyjwt 2.13.0`, `urllib3 2.7.0`, `oauthlib 3.3.1`, `django 6.1.1`, `django-allauth 65.19.2`) - `pyproject.toml:51` (`postulo @ git+...@925e3e9cd35a97617cc45b36ecdde862d04515b1`) - `.forgejo/workflows/ci.yml:47-48,55` and `.forgejo/workflows/release.yml:39-40` (`curl -LsSf https://astral.sh/uv/install.sh | sh`; `uv sync --locked`; no audit step) ## Issue A pip-audit 2.10.1 run on 2026-10-16 against the exported lock reports `pyjwt 2.13.0` with fourteen advisories (PYSEC-2026-4140 to -4152 and -4183; fixed in 2.14.0 / 2.15.0, including HMAC key-handling flaws that allow token forgery and a JWKS redirect-following issue), `urllib3 2.7.0` with three (PYSEC-2026-4175 to -4177, fixed in 2.8.0) and `oauthlib 3.3.1` with one (CVE-2026-49265, fixed in 4.0.0). The lock also holds `django 6.1.1`, whose four security fixes in 6.1.2 pip-audit cannot see (postulo/postulo SEC2-044), and `django-allauth 65.19.2`, behind the releases that move to oauthlib 4. That is 14 + 3 + 1 + 4 = 22 advisories. The plugin pins the core at `925e3e9cd` (2026-10-10, five days and 210 commits behind the core's `56fc9d531`). The pin is not the cause: the core's lock does not constrain a plugin's lock (only `pyproject.toml` floors do), and the plugin's own `uv.lock` has simply never been re-resolved. The plugin's own code uses `httpx` through the guarded client (`pyproject.toml:23`) and imports neither `jwt`, `requests` nor `urllib3`, so these packages are reached only through django-allauth's OpenID Connect sign-in in the plugin's *test* environment. In production a plugin is installed into the core's environment under the core's constraint file (`docker/Dockerfile`, `/app/constraints.txt`), so the core's versions win; this lock describes what the plugin's tests run against and what a developer installs. Hence Low. Nothing would tell anybody: neither workflow runs `pip-audit`, and both install uv from the unversioned `install.sh` (the core pinned it with a checksum in postulo/postulo#790). ## Impact A developer or a CI run of this repository works in an environment with a JWT library that accepts forged tokens under some HMAC configurations and an HTTP stack with open advisories. If a future release of the plugin ever ships its lock (a standalone image, a `uv tool install`), the stale pins ship with it. ## Fix Re-resolve the lock: `uv lock --upgrade` (or `--upgrade-package` for `pyjwt`, `urllib3`, `django`, `django-allauth` and `oauthlib`); upgrading allauth brings oauthlib 4 with it, so the lock comes out clean. Re-pinning the core to its current `main` is worth doing at the same time but moves nothing on its own. Add to `ci.yml` the core's audit step (`uv export --no-emit-project ... | pip-audit --strict`) and the pinned installer (`UV_VERSION`, `UV_INSTALLER_SHA256`). Done when: pip-audit against the exported lock reports nothing and the CI workflow fails on a new advisory. ## Related postulo/postulo-apprise#13 (open) - names this repository's unversioned installer line and missing audit step among "the other five Python plugin repositories", so the CI half is already filed there; the stale lock itself is not. #2 (closed) - "CI, pins and surface imports" of 2026-09-15, about the CI and the core pin, not the lock's advisories. postulo/postulo SEC2-044 and SEC2-045 - the Django and django-allauth lag in the core.
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-dav#31
No description provided.