SEC2-044: The core locks Django 6.1.1 while 6.1.2 (2026-10-06) carries four security fixes, and the weekly audit did not notice #986

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

Found on 2026-10-16 in a read-only security review of postulo at 56fc9d531, 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 (package django, version 6.1.1)
  • pyproject.toml:20 ("django>=6.1,<6.2")
  • .forgejo/workflows/dependencies.yml:22-25 (monthly cron: "23 5 3 * *")
  • .forgejo/workflows/ci.yml:605-628 (the pip-audit step)

Issue

The lock holds django 6.1.1. Django 6.1.2 was published on 2026-10-06 as a security release (docs.djangoproject.com/en/6.1/releases/6.1.2/):

  • CVE-2026-84429 (moderate): quadratic parsing time in parse_header_parameters(), reached by any request carrying a Content-Type or Content-Disposition header, so by an anonymous visitor on the sign-in page or the capture API;
  • CVE-2026-87975 (moderate): model formsets with editable primary keys acting on instances outside the queryset from forged POST data; Postulo's formsets use auto primary keys, so this is probably not reachable here, but it has not been ruled out formset by formset;
  • CVE-2026-77050 (low): very long language codes used as cache keys in get_supported_language_variant(), which Accept-Language and the language picker reach;
  • CVE-2026-87890: GIS rasters, not used.

A pip-audit 2.10.1 run on 2026-10-16 against the exported lock lists django 6.1.1 with no vulnerabilities. The four advisories exist but carry no package or version metadata, so no OSV-fed tool can match them until someone adds it: a coverage gap, not a delay that resolves itself. The audit the threat model relies on ("Dependencies are audited against the advisory databases on every push and weekly") therefore stayed green. The monthly lock upgrade runs on the 3rd, so a release on the 6th waits until 3 November. postulo-templates and postulo-francetravail, re-locked later, already hold django==6.1.2, so the core lags its own plugin repositories.

Impact

An anonymous visitor can make a worker spend quadratic time on a crafted header (denial of service is outside the threat model's scope, which is why this is not rated higher), and the instance runs without the other fixes until somebody looks. More generally, the project's two mechanisms (advisory audit, monthly re-lock) leave a window of up to a month after a framework security release during which CI says nothing.

Fix

uv lock --upgrade-package django to 6.1.2 and run the suite. The new header parser decodes RFC 2231 values without an encoding differently, so re-read the tests that assert on Content-Disposition parsing or uploads: tests/security/test_kind_files.py, test_candidate_file.py, test_captured_pages.py, test_vcard.py, test_backups_page.py, test_downloads_not_cached.py.

Then close the window with a targeted version watch rather than a weekly full re-lock (which moves every package and invites churn): a step in the weekly security job that compares the locked version of a short list (django, django-allauth, gunicorn, cryptography, weasyprint) with PyPI's newest release inside the pyproject.toml range (https://pypi.org/pypi/<pkg>/json, info.version, or uv lock --upgrade-package ... --dry-run) and fails when a newer one has been out for more than seven days.

Done when: uv.lock holds django 6.1.2, and a test beside tests/test_security_audit.py (or the CI step itself) fails while a newer patch release of a watched package has been on PyPI for more than a week.

SEC2-045 - the same lag for django-allauth. SEC2-054 - SECURITY.md promises what the audit cannot see. #233 (closed) - created the monthly upgrade. #583 (closed) - widened the audit's scope. #163 (closed) - the last dependency bumped for a CVE. None covers a security release the advisory database has not recorded.

Found on 2026-10-16 in a read-only security review of `postulo` at `56fc9d531`, 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` (package `django`, version `6.1.1`) - `pyproject.toml:20` (`"django>=6.1,<6.2"`) - `.forgejo/workflows/dependencies.yml:22-25` (monthly `cron: "23 5 3 * *"`) - `.forgejo/workflows/ci.yml:605-628` (the pip-audit step) ## Issue The lock holds `django 6.1.1`. Django 6.1.2 was published on 2026-10-06 as a security release (docs.djangoproject.com/en/6.1/releases/6.1.2/): - CVE-2026-84429 (moderate): quadratic parsing time in `parse_header_parameters()`, reached by any request carrying a `Content-Type` or `Content-Disposition` header, so by an anonymous visitor on the sign-in page or the capture API; - CVE-2026-87975 (moderate): model formsets with editable primary keys acting on instances outside the queryset from forged POST data; Postulo's formsets use auto primary keys, so this is probably not reachable here, but it has not been ruled out formset by formset; - CVE-2026-77050 (low): very long language codes used as cache keys in `get_supported_language_variant()`, which `Accept-Language` and the language picker reach; - CVE-2026-87890: GIS rasters, not used. A pip-audit 2.10.1 run on 2026-10-16 against the exported lock lists `django 6.1.1` with no vulnerabilities. The four advisories exist but carry no package or version metadata, so no OSV-fed tool can match them until someone adds it: a coverage gap, not a delay that resolves itself. The audit the threat model relies on ("Dependencies are audited against the advisory databases on every push and weekly") therefore stayed green. The monthly lock upgrade runs on the 3rd, so a release on the 6th waits until 3 November. `postulo-templates` and `postulo-francetravail`, re-locked later, already hold `django==6.1.2`, so the core lags its own plugin repositories. ## Impact An anonymous visitor can make a worker spend quadratic time on a crafted header (denial of service is outside the threat model's scope, which is why this is not rated higher), and the instance runs without the other fixes until somebody looks. More generally, the project's two mechanisms (advisory audit, monthly re-lock) leave a window of up to a month after a framework security release during which CI says nothing. ## Fix `uv lock --upgrade-package django` to 6.1.2 and run the suite. The new header parser decodes RFC 2231 values without an encoding differently, so re-read the tests that assert on `Content-Disposition` parsing or uploads: `tests/security/test_kind_files.py`, `test_candidate_file.py`, `test_captured_pages.py`, `test_vcard.py`, `test_backups_page.py`, `test_downloads_not_cached.py`. Then close the window with a targeted version watch rather than a weekly full re-lock (which moves every package and invites churn): a step in the weekly `security` job that compares the locked version of a short list (`django`, `django-allauth`, `gunicorn`, `cryptography`, `weasyprint`) with PyPI's newest release inside the `pyproject.toml` range (`https://pypi.org/pypi/<pkg>/json`, `info.version`, or `uv lock --upgrade-package ... --dry-run`) and fails when a newer one has been out for more than seven days. Done when: `uv.lock` holds `django 6.1.2`, and a test beside `tests/test_security_audit.py` (or the CI step itself) fails while a newer patch release of a watched package has been on PyPI for more than a week. ## Related SEC2-045 - the same lag for django-allauth. SEC2-054 - `SECURITY.md` promises what the audit cannot see. #233 (closed) - created the monthly upgrade. #583 (closed) - widened the audit's scope. #163 (closed) - the last dependency bumped for a CVE. None covers a security release the advisory database has not recorded.
tiagoagueda added this to the 0.6.0 milestone 2026-10-17 10:39:22 +00:00
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#986
No description provided.