{ "vulnerabilities": [ { "ID": "AUTHZ-VULN-01", "vulnerability_type": "Horizontal", "externally_exploitable": true, "endpoint": "GET /dossier/{id}/export", "vulnerable_code_location": "/repos/inou-portal/lib/stubs.go:197", "role_context": "user with PermRead on any dossier", "guard_evidence": "lib.DossierGet ignores AccessContext parameter - directly calls entryQuery without authorization", "side_effect": "export complete dossier data including PII and medical records for other users", "reason": "Stub function DossierGet accepts ctx parameter but never uses it, bypassing all authorization checks", "minimal_witness": "1) Create two accounts A and B; 2) Login as A; 3) GET /dossier/{B_id}/export using B's dossier ID; 4) Receive B's complete health records", "confidence": "high", "notes": "Portal layer has weak pre-filter checking IsCareReceiver flag, but lib.DossierGet provides no defense-in-depth" }, { "ID": "AUTHZ-VULN-02", "vulnerability_type": "Horizontal", "externally_exploitable": true, "endpoint": "GET /api/v1/dossiers/{id}", "vulnerable_code_location": "/repos/inou-portal/lib/stubs.go:197", "role_context": "user with valid API Bearer token", "guard_evidence": "v1CanAccess check at API layer, but lib.DossierGet(nil, id) ignores authorization", "side_effect": "read dossier metadata (name, email, DOB, sex) for other users", "reason": "Single layer of defense - v1CanAccess is only check, lib function ignores context", "minimal_witness": "1) Get valid Bearer token; 2) Call GET /api/v1/dossiers/{victim_id}; 3) Bypass depends on v1CanAccess having bugs", "confidence": "med", "notes": "Requires bypassing v1CanAccess check first, but no secondary defense exists" }, { "ID": "AUTHZ-VULN-03", "vulnerability_type": "Horizontal", "externally_exploitable": true, "endpoint": "GET /api/v1/dossiers/{id}/entries", "vulnerable_code_location": "/repos/inou-portal/lib/stubs.go:101", "role_context": "user with valid API Bearer token", "guard_evidence": "Uses lib.SystemAccessorID which bypasses CheckAccess (rbac.go:20)", "side_effect": "list all medical entries for other users' dossiers", "reason": "lib.EntryList called with SystemAccessorID - CheckAccess returns true for system accessor", "minimal_witness": "1) Get valid Bearer token; 2) Call GET /api/v1/dossiers/{victim_id}/entries after bypassing v1CanAccess; 3) Receive all entries", "confidence": "med", "notes": "Requires bypassing v1CanAccess, then SystemAccessorID bypasses lib layer" }, { "ID": "AUTHZ-VULN-04", "vulnerability_type": "Horizontal", "externally_exploitable": true, "endpoint": "GET /api/v1/dossiers/{id}/access", "vulnerable_code_location": "/repos/inou-portal/lib/stubs.go:295-299", "role_context": "user with valid API Bearer token", "guard_evidence": "lib.AccessList has no AccessContext parameter - directly queries access table", "side_effect": "view access control lists showing who has access to a dossier", "reason": "AccessList function fundamentally cannot enforce authorization - no context parameter", "minimal_witness": "1) Get valid Bearer token; 2) Call GET /api/v1/dossiers/{victim_id}/access; 3) Receive access grants if v1CanAccess is bypassed", "confidence": "med", "notes": "Exposes access control metadata, not health data directly" }, { "ID": "AUTHZ-VULN-05", "vulnerability_type": "Horizontal", "externally_exploitable": true, "endpoint": "GET /contact-sheet.webp/{id}", "vulnerable_code_location": "/repos/inou-portal/api/api_contact_sheet.go:99,111", "role_context": "authenticated user with any dossier access", "guard_evidence": "Passes nil context to EntryGet(nil, series.ParentID) and DossierGet(nil, dossierID)", "side_effect": "retrieve contact sheet images and patient names from other users' medical imaging studies", "reason": "Explicitly passes nil to bypass authorization for parent study and dossier lookups", "minimal_witness": "1) Login; 2) Discover valid series ID (via IDOR enumeration); 3) GET /contact-sheet.webp/{series_id}; 4) Receive image and patient name", "confidence": "high", "notes": "Portal proxy does no authorization - blindly forwards to API. API getAccessContextOrFail checks authentication but nil is passed to lookups" }, { "ID": "AUTHZ-VULN-06", "vulnerability_type": "Horizontal", "externally_exploitable": true, "endpoint": "GET /api/v1/images/{id}", "vulnerable_code_location": "/repos/inou-portal/api/api_v1.go:635,655", "role_context": "user with valid API Bearer token", "guard_evidence": "Passes nil to EntryGet(nil, id) and ImageGet(nil, id, opts) - authorization check happens AFTER data retrieval", "side_effect": "retrieve medical imaging files (DICOM, X-rays, MRIs) from other users", "reason": "Authorization via v1CanAccess happens at line 640 AFTER EntryGet at line 635 - data already retrieved from database", "minimal_witness": "1) Get valid Bearer token; 2) Enumerate entry IDs; 3) Call GET /api/v1/images/{entry_id}; 4) Authorization checked post-retrieval", "confidence": "high", "notes": "Post-authorization pattern - data read before permission check, potential for timing attacks even if check passes" }, { "ID": "AUTHZ-VULN-11", "vulnerability_type": "Vertical", "externally_exploitable": true, "endpoint": "POST /dossier/{id}/trackers/respond", "vulnerable_code_location": "/repos/inou-portal/portal/trackers.go:354-358", "role_context": "user with PermRead (read-only access)", "guard_evidence": "Only checks authentication (getLoggedInDossier), NO authorization check for PermWrite on target dossier", "side_effect": "create tracker response entries in dossiers where user only has read access", "reason": "Endpoint validates authentication but not PermWrite permission - any authenticated user can write tracker responses", "minimal_witness": "1) Get PermRead access to victim dossier; 2) POST /dossier/{victim_id}/trackers/respond with tracker data; 3) Entry created despite lacking PermWrite", "confidence": "high", "notes": "CRITICAL: Allows read-only users to modify health data" }, { "ID": "AUTHZ-VULN-12", "vulnerability_type": "Vertical", "externally_exploitable": true, "endpoint": "POST /api/entries", "vulnerable_code_location": "/repos/inou-portal/api/api_entries.go:58-62", "role_context": "authenticated user or localhost", "guard_evidence": "Uses getAccessContextOrSystem which allows localhost bypass, no PermWrite validation before create/update/delete", "side_effect": "create, update, or delete entries in any dossier without PermWrite permission", "reason": "No permission check beyond authentication - lib.EntryModify and lib.EntryAddBatch have no authorization", "minimal_witness": "1) Get authentication; 2) POST /api/entries with create/update/delete operations; 3) Operations succeed without PermWrite check", "confidence": "high", "notes": "CRITICAL: Complete write access bypass. Also localhost requests get SystemContext (full bypass)" }, { "ID": "AUTHZ-VULN-13", "vulnerability_type": "Vertical", "externally_exploitable": true, "endpoint": "POST /dossier/{id}/permissions", "vulnerable_code_location": "/repos/inou-portal/portal/main.go:1403-1442", "role_context": "user with PermManage", "guard_evidence": "No check that grantee != current user, no validation that granted permissions ⊆ grantor permissions", "side_effect": "self-escalate by granting own account higher permissions, or grant permissions you don't have to others", "reason": "Missing self-escalation prevention and permission subset validation", "minimal_witness": "1) Get PermManage on a dossier; 2) POST /dossier/{id}/permissions with email=own email and op_d=1 to grant self PermDelete; 3) Escalation succeeds", "confidence": "high", "notes": "CRITICAL: Permission escalation vulnerability allows PermManage users to gain PermDelete and grant permissions they lack" }, { "ID": "AUTHZ-VULN-14", "vulnerability_type": "Vertical", "externally_exploitable": true, "endpoint": "DELETE /dossier/{id}/files/{fileId}/delete", "vulnerable_code_location": "/repos/inou-portal/portal/upload.go:282-287", "role_context": "user with PermWrite (but not PermDelete)", "guard_evidence": "Checks CanEdit (PermWrite) instead of PermDelete", "side_effect": "delete uploaded medical files without having PermDelete permission", "reason": "Endpoint claims to require PermDelete but actually only checks CanEdit which maps to PermWrite", "minimal_witness": "1) Get PermWrite access to dossier; 2) DELETE /dossier/{id}/files/{file_id}/delete; 3) File deleted despite lacking PermDelete", "confidence": "high", "notes": "Permission escalation from PermWrite to PermDelete for file deletion operations" } ] }