Skip to content

chore: backport security improvements from audit#18

Merged
amrtgaber merged 4 commits into
mainfrom
chore/backport-from-audit
Apr 12, 2026
Merged

chore: backport security improvements from audit#18
amrtgaber merged 4 commits into
mainfrom
chore/backport-from-audit

Conversation

@amrtgaber
Copy link
Copy Markdown
Contributor

@amrtgaber amrtgaber commented Apr 12, 2026

Summary

Backports template-level fixes discovered during a security / analytics / legal audit across projects spawned from this template. Full plan in BACKPORT_FROM_AUDIT.md (templates root).

Changes

Security

  • feat: 1MB request body size middleware in app/main.py. FastAPI/Starlette enforces no default limit, so without this a malicious client could POST a multi-GB JSON payload and the server would happily try to parse it. Returns HTTP 413 when Content-Length exceeds the threshold.
  • feat(schemas): add Field(max_length=...) bounds to user-supplied strings.
    • NoteBase.body → 10,000 chars (was unbounded)
    • UserCreate.name / UserUpdate.name → 100 chars (were unbounded)
    • UserRead.name intentionally left unbounded (response shape, data originates from our DB)
    • Demonstrates the pattern so new projects copy it.

Observability

  • feat(logging): bind user_id to structlog contextvars on authentication. Wraps the fastapi-users current_active_user and current_superuser dependencies transparently so every log emitted during an authenticated request carries user_id alongside the existing request_id. No caller changes required — the wrapping happens at the symbol level in app/auth/users.py and FastAPI's DI chain handles the rest.

Scaffolding

  • chore: add top-level permissions: contents: read to .github/workflows/ci.yml (least-privilege GITHUB_TOKEN).
  • chore: add .github/CODEOWNERS catch-all placeholder (* @amrtgaber) so spawned projects get review enforcement from day one.

Test plan

  • uv run ruff check . — clean
  • uv run ruff format --check . — clean
  • uv run pytest — 21/21 passing
  • Manual: POST a request with Content-Length: 2000000 and verify 413 response
  • Manual: authenticated request and verify user_id appears in structured log output alongside request_id
  • Manual: POST a note with a 20,000-char body and verify 422 validation error

FastAPI/Starlette has no default body size limit. Add a middleware
that returns 413 when Content-Length exceeds 1MB, protecting
against unbounded JSON payload DoS.
Wrap fastapi-users current_active_user and current_superuser so
every log emitted during an authenticated request automatically
carries user_id alongside request_id. No caller changes required.
Demonstrates the Field(max_length=...) pattern on NoteBase.body
(10k chars) and UserCreate/UserUpdate.name (100 chars). Unbounded
string inputs allow malicious clients to store arbitrarily large
values. Response schemas (UserRead) are left unbounded since the
data originates from our own DB.
- CI: restrict GITHUB_TOKEN to contents:read (least privilege)
- .github/CODEOWNERS catch-all placeholder for review enforcement
@amrtgaber amrtgaber merged commit bd7d8ff into main Apr 12, 2026
2 checks passed
@amrtgaber amrtgaber deleted the chore/backport-from-audit branch April 12, 2026 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant