Files
ledgerdock/REPORT.md

7.5 KiB

Security Analysis Report

Date: 2026-03-02 Repository: /Users/bedas/Developer/GitHub/dcm Scope: backend FastAPI API and worker, frontend React app, Docker runtime configuration, and local .env posture.

Executive Verdict

Current state is not production ready.

  • Blocking code-level issues exist and should be fixed before production exposure.
  • Additional user-dependent deployment risks are present in .env and runtime defaults. Per request, these are listed as MUST KNOW and not marked as blocking.

Method and Coverage

Performed a read-only static review of:

  • API auth, authorization, upload and file handling, routing, settings, and worker pipelines.
  • Frontend auth token handling and preview rendering behavior.
  • Docker and environment defaults affecting network and secret posture.
  • Existing security-focused tests and basic frontend API tests.

Blocking Security Issues (Code-Level)

1) High - No abuse controls on expensive authenticated endpoints

Impact:

  • Any authenticated user can repeatedly trigger high-cost operations (upload processing, OCR, summarization, routing, indexing), causing queue saturation, infrastructure exhaustion, and external provider cost abuse.

Exploit path:

  • Repeated POST /api/v1/documents/upload
  • Repeated POST /api/v1/documents/{document_id}/reprocess

Evidence:

  • Upload endpoint has size limits but no rate/volume quota checks: backend/app/api/routes_documents.py:665-985.
  • Reprocess endpoint has no rate/cooldown checks: backend/app/api/routes_documents.py:958-985.
  • A Redis rate limiter exists but is currently used for markdown export only: backend/app/services/rate_limiter.py:16-42 and backend/app/api/routes_documents.py:100-120.

Remediation:

  • Add per-user and per-IP rate limiting to upload and reprocess endpoints.
  • Add per-user daily/rolling quotas (documents, bytes, reprocess calls).
  • Add queue depth backpressure and reject or defer requests when saturated.
  • Add alerting for anomalous request and job-enqueue rates.

2) Medium - API docs and schema are exposed by default

Impact:

  • Unauthenticated endpoint discovery and contract reconnaissance are easier (/docs, /redoc, /openapi.json).

Exploit path:

  • Remote probing of public API metadata when service is internet-reachable.

Evidence:

  • FastAPI app is created with default docs behavior and no production gating: backend/app/main.py:37.

Remediation:

  • Disable docs in production (docs_url=None, redoc_url=None, openapi_url=None) or
  • Restrict these routes at reverse proxy / edge to trusted admin networks.

3) Medium - Bearer token stored in browser sessionStorage

Impact:

  • Any successful XSS on the frontend origin can steal bearer tokens and replay them.

Exploit path:

  • Malicious script execution on app origin reads sessionStorage and exfiltrates Authorization token.

Evidence:

  • Token persisted in sessionStorage and injected into Authorization header: frontend/src/lib/api.ts:39-42, frontend/src/lib/api.ts:61-67, frontend/src/lib/api.ts:84-95, frontend/src/lib/api.ts:103-112.

Remediation:

  • Prefer HttpOnly Secure SameSite cookies for session auth, plus CSRF protection.
  • If bearer-in-JS remains, enforce strict CSP, remove inline script execution, and add strong dependency hygiene.

MUST KNOW (User-Dependent, Non-Blocking Per Request)

A) Current .env is development-oriented and exposed beyond localhost

Why this matters:

  • Service currently binds to all interfaces and uses development settings, which is unsafe for direct internet exposure.

Evidence:

  • APP_ENV=development: .env:1
  • HOST_BIND_IP=0.0.0.0: .env:2
  • PUBLIC_BASE_URL=http://...: .env:33
  • Broad CORS for localhost and LAN host: .env:34

Action:

  • Set production values (APP_ENV=production, HTTPS base URL, strict CORS, host binding behind hardened reverse proxy).

B) Provider SSRF protections are disabled in active env

Why this matters:

  • Allowing HTTP, private network targets, and empty allowlist can permit unsafe outbound model-provider endpoints.

Evidence:

  • Active .env: PROVIDER_BASE_URL_ALLOW_HTTP=true, PROVIDER_BASE_URL_ALLOW_PRIVATE_NETWORK=true, PROVIDER_BASE_URL_ALLOWLIST=[] at .env:29-31.
  • Compose defaults are permissive if env is not hardened: docker-compose.yml:55-57, docker-compose.yml:100-102.

Action:

  • For production set: ALLOW_HTTP=false, ALLOW_PRIVATE_NETWORK=false, explicit host allowlist.

C) Sensitive model and payload text logging is enabled in active env

Why this matters:

  • Prompt/response and payload text may include confidential document content and credentials, increasing breach impact.

Evidence:

  • Active .env enables both flags: .env:22-23.
  • Code defaults are safer (false): backend/app/core/config.py:60-61.

Action:

  • Disable in production unless explicitly required for short-term diagnostics.
  • Apply strict retention and access controls if temporarily enabled.

D) Redis transport/auth hardening depends on env mode and URL

Why this matters:

  • Current env uses redis:// with auto security/tls mode; this is not suitable for untrusted network paths.

Evidence:

  • Active .env: REDIS_URL=redis://..., REDIS_SECURITY_MODE=auto, REDIS_TLS_MODE=auto at .env:10-12.
  • Strict checks are triggered by production mode when auto is used: backend/app/core/config.py:157-171.

Action:

  • In production use rediss://, REDIS_SECURITY_MODE=strict, REDIS_TLS_MODE=required.

E) Frontend container runs a development server

Why this matters:

  • Vite dev server is not intended as a hardened production serving layer.

Evidence:

  • Frontend container command runs npm run dev: frontend/Dockerfile:20.
  • dev script maps to Vite dev mode: frontend/package.json:7.

Action:

  • Build static assets and serve behind a production-grade web server/reverse proxy.

F) Login throttle IP identity depends on proxy topology

Why this matters:

  • Throttle identity uses request.client.host; if a proxy masks client IPs, lockout behavior may be inaccurate.

Evidence:

  • IP extraction uses transport client host directly: backend/app/api/routes_auth.py:32-35.

Action:

  • Ensure trusted proxy configuration preserves real client IP semantics before internet deployment.

Validation Commands and Outcomes

Preflight:

  • command -v git -> passed (/usr/bin/git)
  • git rev-parse --is-inside-work-tree -> passed (true)
  • git status --short -> clean before work

Security-related backend tests:

  • PYTHONDONTWRITEBYTECODE=1 /Users/bedas/Developer/Python/global_venv/bin/python backend/tests/test_security_controls.py -> passed (34 tests)
  • PYTHONDONTWRITEBYTECODE=1 /Users/bedas/Developer/Python/global_venv/bin/python backend/tests/test_upload_request_size_middleware.py -> passed (3 tests)
  • PYTHONDONTWRITEBYTECODE=1 /Users/bedas/Developer/Python/global_venv/bin/python backend/tests/test_app_settings_provider_resilience.py -> passed (6 tests)
  • PYTHONDONTWRITEBYTECODE=1 /Users/bedas/Developer/Python/global_venv/bin/python backend/tests/test_processing_log_retention_settings.py -> passed (5 tests)

Frontend auth-client test:

  • npm run test (in frontend/) -> passed

Note:

  • pytest is not installed in /Users/bedas/Developer/Python/global_venv/bin/python, so direct module execution via unittest entrypoints was used for backend test files.

Residual Risk and Coverage Limits

  • No dynamic penetration test was run against a live deployed stack.
  • No dependency CVE audit (pip-audit, npm audit) was run in this turn.
  • Reverse proxy, firewall, TLS termination, and cloud/network policy were not reviewed.