Files
ledgerdock/REPORT.md

98 lines
5.3 KiB
Markdown

# 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.