fix(security): patch cryptography CVEs, upgrade pip at build, harden /auth/upgrade

- requirements: cryptography >=46.0.7 (was pinned <46, which excluded the fix for
  the CVEs pip-audit flagged in our Fernet/crypto library). pip-audit now clean.
- Dockerfile: upgrade pip before installing deps (patches installer-level CVEs).
- auth: /auth/upgrade now defaults to the least-privileged read scope; only an
  explicit access=write requests the write scope.
This commit is contained in:
npeter83 2026-06-14 05:59:34 +02:00
parent 94a51b1b43
commit c12e776706
3 changed files with 6 additions and 5 deletions

View file

@ -16,7 +16,7 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
WORKDIR /app WORKDIR /app
COPY backend/requirements.txt . COPY backend/requirements.txt .
RUN pip install -r requirements.txt RUN pip install --upgrade pip && pip install -r requirements.txt
COPY backend/ . COPY backend/ .
COPY --from=frontend /fe/dist ./app/static_spa COPY --from=frontend /fe/dist ./app/static_spa

View file

@ -213,13 +213,14 @@ def current_user(request: Request, db: Session = Depends(get_db)) -> User:
@router.get("/upgrade") @router.get("/upgrade")
async def upgrade( async def upgrade(
request: Request, access: str = "write", user: User = Depends(current_user) request: Request, access: str = "read", user: User = Depends(current_user)
): ):
"""Incremental consent for the onboarding wizard. `access=read` grants YouTube """Incremental consent for the onboarding wizard. `access=read` grants YouTube
read-only (enough to build the feed); `access=write` additionally grants management read-only (enough to build the feed); `access=write` additionally grants management
(unsubscribe). The shared callback stores whatever Google returns, so `can_read` / (unsubscribe). The shared callback stores whatever Google returns, so `can_read` /
`can_write` flip on once granted.""" `can_write` flip on once granted. Anything other than an explicit `write` defaults to
scope = READ_SCOPES if access == "read" else WRITE_SCOPES the least-privileged read scope."""
scope = WRITE_SCOPES if access == "write" else READ_SCOPES
return await oauth.google.authorize_redirect( return await oauth.google.authorize_redirect(
request, request,
settings.oauth_redirect_url, settings.oauth_redirect_url,

View file

@ -11,4 +11,4 @@ feedparser>=6.0,<7.0
apscheduler>=3.10,<4.0 apscheduler>=3.10,<4.0
py3langid>=0.3,<1.0 py3langid>=0.3,<1.0
itsdangerous>=2.1,<3.0 itsdangerous>=2.1,<3.0
cryptography>=42,<46 cryptography>=46.0.7,<47