chore(deps): floor-pin pydantic-settings >=2.14.2 + msgpack >=1.2.1 for clean pip-audit

pip-audit flagged two advisories at the resolved versions in the venv.
  Neither is reachable in shipped Bambuddy, but the pins are taken so
  the audit stays clean and a future reachable advisory in either
  package isn't masked by existing noise.

  pydantic-settings 2.14.2 patches GHSA-4xgf-cpjx-pc3j —
  NestedSecretsSettingsSource with secrets_nested_subdir=True followed
  symlinks pointing outside the configured secrets_dir, reading
  out-of-tree files into settings values and bypassing the documented
  secrets_dir_max_size cap. Affected: >=2.12.0, <2.14.2. Bambuddy uses
  pydantic-settings only for env-var-backed config; the secrets-dir
  loader is not used (grep clean on NestedSecretsSettingsSource /
  secrets_nested_subdir / secrets_dir under backend/).

  msgpack 1.2.1 patches GHSA-6v7p-g79w-8964 — reusing an Unpacker
  instance after it caught an error can crash with SEGV, which is a
  DoS vector on untrusted input. msgpack is not a runtime dep of
  Bambuddy; it enters the tree only as a transitive of CacheControl,
  itself pulled by pip-audit (the very tool that surfaced the
  advisory). Pin placed in requirements-dev.txt next to pip-audit so
  it travels with the security-scan tooling rather than implying a
  runtime use.
This commit is contained in:
maziggy
2026-06-25 15:27:17 +02:00
parent c236fdc650
commit 0b43ac0d25
3 changed files with 10 additions and 1 deletions
+2
View File
@@ -25,6 +25,8 @@ All notable changes to Bambuddy will be documented in this file.
- **Vite 7 → 8 major bump** — Bambuddy's frontend now builds with Vite 8 (`^7.3.2` → `^8.0.16`) and the matching plugin-react release (`@vitejs/plugin-react` `^5.1.1` → `^5.2.0`). Headline architectural change: Vite 8 swaps Rollup for **Rolldown** as the default bundler — same plugin contract, Rust-backed core, slightly different chunk layout / output bytes (no functional regression). The bump also lifts the transitive `esbuild` floor to 0.28.1, which closes the last open advisory in the audit chain. **Bambuddy-side surface audited:** `vite.config.ts` uses only stable contracts that survived the v8 cut — `defineConfig`, the `Connect` type, the custom `serveGcodeViewer` `configureServer` middleware plugin (proxies `/gcode-viewer/*` to the repo's sibling `gcode_viewer/` directory in dev), the `server.proxy` with WebSocket upgrade for `/api/v1/ws`, `build.outDir`/`emptyOutDir`/`chunkSizeWarningLimit`, and `resolve.alias` for `@`. `base: '/'` regression guard from #1221 is unaffected. No SSR, no library mode, no CSS preprocessors, no exotic plugins. `vitest@4.1.8` already accepts vite 8 in its peer range (`^6 || ^7 || ^8`); no test-runner bump required. **Node:** vite 8 requires `^20.19.0 || >=22.12.0`; CI Node 20.x line satisfies this. **What this is NOT:** plugin-react v6 — that line requires `babel-plugin-react-compiler` + `@rolldown/plugin-babel` as peers and is a separate scope. `npm run build`, `npm run lint`, `npx vitest run` all clean; `npm audit` clean.
- **Frontend dependency bumps** — Routine version updates across the runtime, build, and test dependency surface. **Runtime:** `dompurify` 3.4.0 → 3.4.10. `package.json` floor raised from `^3.4.0` to `^3.4.10` so fresh installs cannot land on the deprecated 3.4.4 release. Three call sites use string-output sanitisation (`frontend/src/pages/MakerworldPage.tsx`, `frontend/src/pages/ProjectDetailPage.tsx`, `frontend/src/components/ProjectPageModal.tsx`); release notes 3.4.1 → 3.4.10 reviewed for behavioural changes — 3.4.4 widened the default allow-list with `selectedcontent` + `command` + `commandfor` (all valid modern HTML, harmless for our two default-allow-list call sites), and `ProjectPageModal` is unaffected anyway because it sets an explicit `ALLOWED_TAGS` / `ALLOWED_ATTR` whitelist. **Build / lint / test tooling (transitive, dev-only):** `@babel/core` 7.29.0 → 7.29.7 (pulled by `@vitejs/plugin-react` and `eslint-plugin-react-hooks`), `vite` 7.3.2 → 7.3.5, `markdown-it` 14.1.1 → 14.2.0 (pulled by `@tiptap/extension-link` → `@tiptap/pm` → `prosemirror-markdown`; Bambuddy never calls `markdown-it.render` directly so the change is transparent), `js-yaml` 4.1.1 → 4.2.0 (pulled by `eslint`), `form-data` 4.0.5 → 4.0.6 + `ws` 8.20.1 → 8.21.0 (both pulled by `jsdom` in the test runtime). All bumps inside existing semver ranges except `dompurify`. No source changes required.
- **`dompurify` 3.4.10 → 3.4.11** — Follow-up patch closes a moderate-severity advisory affecting `setConfig()` callers: the previous hook clone-guard added in 3.4.7 could be bypassed via `setConfig()`, leaving a permanent `ALLOWED_ATTR` pollution that the next `sanitize()` call inherited. **Bambuddy's exposure is nil** — `git grep DOMPurify.setConfig` returns zero hits across the entire codebase; all three sanitisation sites (`frontend/src/pages/MakerworldPage.tsx`, `frontend/src/pages/ProjectDetailPage.tsx`, `frontend/src/components/ProjectPageModal.tsx`) call `DOMPurify.sanitize(html)` or `DOMPurify.sanitize(html, {ALLOWED_TAGS, ALLOWED_ATTR})` directly, never through `setConfig()`. The bump is taken as defence-in-depth to keep XSS-sensitive surface area current and to silence `npm audit` so future audit-fix runs don't auto-bundle unintended changes. **Mechanical lockfile bump only:** the existing `^3.4.10` range already permitted 3.4.11, so `package.json` is unchanged; `package-lock.json` updates the resolved URL + integrity hash for the one entry. Verification: `npm audit` reports 0 vulnerabilities, `MakerworldPage.test.tsx`'s 12 DOMPurify sanitisation cases pass, `npm run build` clean.
- **Precautionary floor pins for pydantic-settings 2.14.2 + msgpack 1.2.1** — pip-audit surfaced two advisories that are not reachable in shipped Bambuddy but were flooring at vulnerable versions. **`pydantic-settings` 2.0.0 → 2.14.2** in `requirements.txt` clears GHSA-4xgf-cpjx-pc3j (`NestedSecretsSettingsSource` with `secrets_nested_subdir=True` follows symbolic links pointing outside the configured `secrets_dir`, reading out-of-tree files into settings values and bypassing the documented `secrets_dir_max_size` cap; affected `>=2.12.0,<2.14.2`). **Exposure: nil.** `grep -rn "NestedSecretsSettingsSource\|secrets_nested_subdir\|secrets_dir" backend/` returns zero hits — Bambuddy uses pydantic-settings only for env-var-backed config, never for the secrets-dir loader. **`msgpack` 1.2.1** floor-pinned in `requirements-dev.txt` next to `pip-audit>=2.7.0` to clear GHSA-6v7p-g79w-8964 (an `Unpacker` instance reused after catching an error can crash with SEGV; under repeated unpacking of untrusted input from an external source, this is a DoS vector). **Exposure: nil.** `grep -rn "import msgpack\|from msgpack" backend/` returns zero hits — msgpack enters Bambuddy's tree only as a transitive of `CacheControl`, which is itself pulled by `pip-audit` (the very tool that produced the report). Not a runtime dep of the shipped app. Both pins are taken as defence-in-depth / audit hygiene so the next `pip-audit` run is clean and a future *reachable* advisory in either package isn't masked by the existing noise. No code change, no behavioural change, no test change.
- **Backend dependency security floor raises (cryptography / python-multipart / starlette)** — pip-audit December 2026 cycle surfaced six advisories across three direct deps; floors in `requirements.txt` lifted to the documented fix releases, plus one transitive co-bump for resolver compatibility. **`cryptography` 46.0.7 → 48.0.1 floor** (resolver picks 49.0.0 within the new floor) — clears GHSA-537c-gmf6-5ccf (non-contiguous Python buffer handling that could overflow on APIs accepting buffer protocol input). **Release-notes audit (done before bump):** v47.0.0 dropped Python 3.8 + OpenSSL 1.1.x + binary elliptic curves (SECT*) + Camellia + CFB/OFB/CFB8 modes (moved to `cryptography_decrepit`); v48.0.0 dropped `PUBLIC_KEY_TYPES` / `PRIVATE_KEY_TYPES` type aliases. Bambuddy's grep is clean across every one of those: `core/encryption.py` uses Fernet (AES-128-CBC + HMAC), `services/spoolbuddy_ssh.py` uses ed25519, `services/virtual_printer/certificate.py` uses RSA + x509 + ExtendedKeyUsageOID. Python 3.13 + OpenSSL 3.x on container, so the version-floor bumps are no-ops for us. **`python-multipart` 0.0.27 → 0.0.31 floor** (resolver picks 0.0.32) — clears CVE-2026-53538/53539/53540 in the multipart parser surface (boundary length capped at 256 bytes, RFC 2231 continuation handling, Content-Length non-negative validation, bounded header field name size before validation). **Behavioural changes audited:** 0.0.30 stopped recognising RFC 2231/5987 extended `filename*` / `name*` parameters in incoming bodies — Bambuddy emits these on outgoing Content-Disposition response headers (`utils/http.py:17`) but doesn't parse them on the request side, and clients that include both `filename=` and `filename*=` keep working via the plain `filename=` fallback (slight cosmetic difference for non-ASCII filenames in uploads). 0.0.30 also tightened form-urlencoded parsing to treat only `&` as field separator — every Bambuddy client (browser, BambuStudio, OrcaSlicer) already uses `&`. **`starlette` 1.1.0 → 1.3.1 floor** — clears CVE-2026-54282/54283 (FormParser `max_part_size` / `max_fields` limits now actually enforced after being declared-but-ignored in earlier releases; `StaticFiles.lookup_path` rejects absolute paths; `FileResponse` clamps oversized suffix range requests; `URL.replace()` IndexError fix). **Critical pre-bump check:** the newly-enforced `max_part_size=1MB` default would have broken every file upload (`UploadFile = File(...)` in `inventory.py:1127`, `projects.py:886/1053/1780`, `library.py:1787`, `local_presets.py:82`, `external_links.py:166`, `local_backup.py`) if it applied to file streams. Inspected the `MultiPartParser.on_part_data` source: the size check at `if self._current_part.file is None:` only fires for **text** form fields, not file streams — so file uploads of arbitrary size still pass through unaffected. Text form bodies in Bambuddy are login credentials and similar small values, well under the 1MB ceiling. **Side rename:** `backend/app/api/routes/mfa.py:470/1364/1428` replaces 3 references of `status.HTTP_422_UNPROCESSABLE_ENTITY` (deprecated in starlette 1.3.x) with `HTTP_422_UNPROCESSABLE_CONTENT`. Same 422 wire status; silences the 3 deprecation warnings under our own ownership (the two remaining warnings come from FastAPI internals — upstream's to fix). **`pyopenssl` 26.0.0 → 26.3.0 floor** — **NOT a security fix**; required because pyOpenSSL `<26.3.0` caps `cryptography<47` in its install_requires, so without an explicit floor the resolver either downgrades cryptography below the GHSA-537c-gmf6-5ccf fix line or installs an inconsistent pair (pip's resolver warns but proceeds). Bambuddy has no direct `from OpenSSL ...` imports — pyOpenSSL is pulled transitively by `asyncssh` + `pywebpush`. **Verification:** `pip-audit` clean, `pip check` clean, `ruff check backend/` clean, backend `pytest -n 30` 6167/6167 in 86.55s. No DB migration, no API surface change, no permission change, no frontend change.
### Added
+4
View File
@@ -18,5 +18,9 @@ pyOpenSSL>=26.0.0
# Security scanning
bandit[sarif]>=1.7.0
pip-audit>=2.7.0
# Transitive of pip-audit→CacheControl. 1.2.1 patches GHSA-6v7p-g79w-8964
# (Unpacker SEGV/DoS on reuse after caught error). Not a runtime dep of
# Bambuddy — pinned here so the audit stays clean.
msgpack>=1.2.1
# Secrets scan: gitleaks (Go binary, not a Python package).
# Install: go install github.com/zricethezav/gitleaks/v8@latest
+4 -1
View File
@@ -21,7 +21,10 @@ greenlet>=3.0.0
# Pydantic
pydantic>=2.0.0
pydantic-settings>=2.0.0
# 2.14.2 patches GHSA-4xgf-cpjx-pc3j (NestedSecretsSettingsSource follows
# symlinks out of secrets_dir). Bambuddy does not use that source — pin
# is precautionary so the audit stays clean.
pydantic-settings>=2.14.2
# Transitive of pydantic-settings, floor-pinned to patch CVE-2026-28684 (dotenv 1.2.1)
python-dotenv>=1.2.2