6319552675
- IDOR (HIGH): DocumentController download/delete now verify document.clubId matches TenantContext; returns 403 on mismatch via new loadOwnedDocument() helper - Path Traversal (HIGH): DocumentService.sanitizeFilename() strips path components, removes control/reserved chars, caps at 200 chars, falls back to UUID. Applied to uploadDocument() and archiveProtocol() - JWT Dev Secret (HIGH): @PostConstruct guard in JwtService throws IllegalStateException if secret null/<32 chars/equals fail-loud marker. application.properties default replaced with CHANGE_ME_IN_PRODUCTION_THIS_WILL_FAIL_ON_STARTUP placeholder (env var CANNAMANAGE_SECURITY_JWT_SECRET set in docker-compose.yml; test profiles have their own valid secrets) - SecurityConfig (MEDIUM): explicit /api/v1/documents/** matcher with hasAnyRole(ADMIN, STAFF, MEMBER) for defense-in-depth Verified: Docker rebuild healthy, backend starts cleanly (JWT guard accepts env var), Playwright 203 pass (2 pre-existing login failures unrelated — dev compose profile has no seed users; admin@test.de only loaded via docker-compose.test.yml)