Files
ledgerdock/REPORT.md

5.3 KiB

Security Production Readiness Report

Date: 2026-03-02 Repository: /Users/bedas/Developer/GitHub/dcm Assessment type: Static code and configuration review with targeted local security test execution

Verdict

Not production ready.

Reason: one blocking, code-level access-control and data-disclosure issue was found.

Preflight Results

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

Validation Commands And Outcomes

  • /Users/bedas/Developer/Python/global_venv/bin/python -m unittest backend/tests/test_security_controls.py -> pass (32 tests)
  • /Users/bedas/Developer/Python/global_venv/bin/python -m unittest backend/tests/test_upload_request_size_middleware.py -> pass (3 tests)
  • /Users/bedas/Developer/Python/global_venv/bin/python -m unittest backend/tests/test_app_settings_provider_resilience.py -> pass (6 tests)

Blocking Security Findings

High: Non-global catalog presets are exposed to all authenticated users

  • Severity: High (blocking)
  • Why this is blocking:
    • The settings model supports global_shared scope for predefined paths and tags, but the user-accessible discovery endpoints return all predefined entries without filtering by this scope.
    • This breaks intended discoverability boundaries and leaks admin-curated non-global taxonomy metadata to standard users.
  • Impact:
    • Information disclosure across role boundaries for internal path and tag catalogs.
    • Reduced separation between admin-only and user-visible metadata.
  • Exploit path:
    • Any authenticated non-admin user calls GET /api/v1/documents/paths and GET /api/v1/documents/tags.
    • Endpoint responses include every predefined path or tag value regardless of global_shared state.
  • Evidence:
    • backend/app/api/routes_documents.py:399-403 and backend/app/api/routes_documents.py:423-427 include all predefined tags and paths.
    • backend/app/schemas/settings.py:145 and backend/app/schemas/settings.py:159 define global discoverability scope.
    • backend/app/services/app_settings.py:709-710, backend/app/services/app_settings.py:730, backend/app/services/app_settings.py:758-759, and backend/app/services/app_settings.py:779 preserve global_shared state in normalized settings.
  • Required remediation:
    • Filter predefined entries returned by user-facing discovery endpoints by role and global_shared.
    • Keep full catalog visibility for admins only.
    • Add regression tests for non-admin path/tag discovery with mixed global_shared values.

MUST KNOW User-Dependent Risks (Not Blocking Per Request)

These items are deployment, environment, or proxy dependent and are therefore not marked blocking per request requirements.

High: Development-first runtime defaults can be promoted to production if not overridden

  • Evidence:
    • .env.example:5 (APP_ENV=development)
    • .env.example:36-38 (PROVIDER_BASE_URL_ALLOW_HTTP=true, PROVIDER_BASE_URL_ALLOW_PRIVATE_NETWORK=true, empty allowlist)
    • .env.example:14-16 (redis://, REDIS_SECURITY_MODE=compat, REDIS_TLS_MODE=allow_insecure)
    • .env.example:40-41 (PUBLIC_BASE_URL on HTTP, local CORS defaults)
    • docker-compose.yml:56-57, docker-compose.yml:64-66, docker-compose.yml:101-102, docker-compose.yml:106-107
  • Risk:
    • Weak outbound provider constraints, plaintext internal transport defaults, and non-production environment posture can persist in live deployments.

Medium: Login throttle IP identity depends on proxy trust model

  • Evidence:
    • backend/app/api/routes_auth.py:32-35 uses request.client.host only.
  • Risk:
    • Behind reverse proxies, all clients may collapse to proxy IP, increasing lockout abuse and reducing attribution quality.

Medium: API documentation endpoints are exposed by default

  • Evidence:
    • backend/app/main.py:37 creates FastAPI(...) with default docs behavior.
    • README explicitly references /docs as available.
  • Risk:
    • Public endpoint inventory and schema visibility in exposed deployments.

Medium: Bearer token is stored in browser sessionStorage

  • Evidence:
    • frontend/src/lib/api.ts:41, frontend/src/lib/api.ts:61-67, frontend/src/lib/api.ts:84-94
  • Risk:
    • Any successful frontend XSS can exfiltrate active session tokens.

Low: Typesense transport defaults to HTTP on internal network

  • Evidence:
    • docker-compose.yml:66-67, docker-compose.yml:107-108
  • Risk:
    • Acceptable for isolated local networks, but not suitable for untrusted or cross-host network links.

Security Controls Confirmed Present

  • Login brute-force throttling with lockout and Retry-After handling.
  • Owner-scoped access checks for non-admin document operations.
  • Provider base URL validation with allowlist and DNS revalidation hooks.
  • Upload request size and archive extraction guardrails.
  • Processing log redaction and metadata-only persistence defaults.

Coverage Limits

  • No dependency CVE audit was executed in this run.
  • This report is based on repository code, configuration templates, and available local tests.

Production Decision

Current state is not production ready because of the blocking catalog discoverability exposure.

After remediating that issue, production readiness still depends on strict deployment choices for environment variables, proxy trust configuration, TLS, and frontend hardening.