$1, $2…) — no string interpolation in any querybegin_tenant_tx sets app.current_tenant_id via bound set_config() — not format stringsCommand::new with user-supplied input anywhere in codebasealg:none bypass impossiblevalidate_exp, validate_nbf, issuer and audience all enforced in decode_jwt()JWT_LEEWAY_SECS)auth.rs:42 — raw JWT library error forwarded to client via format!("Invalid token: {e}"). Leaks "ExpiredSignature" or "InvalidIssuer" details. Log server-side; return generic "Invalid token" to caller.storage_key excluded from DocumentResponse — confirmed at domain/document.rs:45–80error.rs:38–41 hides all detailsmiddleware.rs clearly labeled test-only.gitignore covers .env, .env.*, *.log, *.pem, *.keyDocument struct derives Serialize (includes storage_key) — API correctly uses DocumentResponse; low risk but tracktenant_id set via set_config() in every transaction — RLS cannot be bypassed without a transactionauth.require_roles() before any data access; no endpoint is unguardedtenant-admin / super-admin; writes require editor+; reads require viewer+/health and /ready unauthenticated — by design for liveness probes; no tenant data exposedcc-debian12:nonroot), USER nonroot:nonroot — minimal attack surfacemax_body_size configured (default 1 MiB) but NOT applied in main.rs — no web::JsonConfig or web::PayloadConfig registered; actix-web default 256 KB applies instead. Config is dead code.cors_allowed_origins parsed for awareness; gateway config must be verified before productionserde_json deserialization — no unsafe or custom pathsdomain/document.rs:100–133cargo-audit not installed — automated advisory scan could not be runcargo audit not in CI pipeline (ci-deploy.yml) — no automated dependency scanningCargo.lock committed — enables reproducible builds and future advisory scanningtracing-subscriber with env-filtercorrelation_id propagated from X-Correlation-Id header or generated as UUID through all service callscargo-audit not installed.cargo install cargo-auditcargo audit
middleware.rs is clearly labeled test-only with explicit security notice. .gitignore excludes .env, *.pem, *.key.unsafe { env::set_var() / env::remove_var() }
#[cfg(test)] only. Thread-safe via Mutex<()> (ENV_LOCK). No unsafe in production code paths.| # | Finding | Effort | Impact | Action |
|---|---|---|---|---|
| 1 | Add cargo audit to CI pipeline |
Low | High | cargo install cargo-audit && cargo audit — add after lint step in ci-deploy.yml |
| 2 | Sanitize JWT error in Unauthorized response | Low | Medium | src/api/auth.rs:42 — log {e} server-side via tracing::warn; return generic "Invalid token" to client |
| 3 | Wire max_body_size into actix middleware |
Low | Medium | main.rs — add web::JsonConfig::default().limit(config.max_body_size) and web::PayloadConfig::default().limit(...) |
| 4 | Verify Traefik gateway CORS & rate-limiting config | Medium | High | Required before production per ADR-001. Confirm Traefik middleware applied to all docstore routes. |
log_audit returns AppResult<()> and callers use ?, enforced at compile time; mutations are blocked if audit write failsnonroot:nonroot user — no shell, no package manager, minimal attack surface at runtimealg:none bypass impossiblestorage_key correctly excluded from DocumentResponse — internal storage paths never reach API consumersdeleted_at timestamp