The Target
A telehealth platform that connects members with healthcare providers for therapy, medical consultations, and other virtual visits. Members book visits through the API, providers get notified, and the platform manages the entire session lifecycle including care records.
The Discovery
I created two test accounts and started testing the visit creation flow. The POST endpoint for creating pending visits takes a member_id in the request body. I swapped Account B's member ID into the request while authenticating as Account A. The visit was created successfully for Member B, and a real provider was notified.
The PUT endpoint for modifying visits had the same problem. No ownership check at all. I could change the visit status, reassign it to a different member, or mark it as completed.
The Attack Chain
Create visit for any member: Using Account A's token, I created a therapy visit assigned to Member B. The server accepted it, assigned a provider, and sent them a notification (priority_notified: 1). The visit appeared in the victim's account.
Denial of healthcare: While the attacker's unauthorized visit was active, the victim could not schedule their own legitimate visit. The API returned "You already have a visit in progress." The attacker effectively blocked the victim from accessing telehealth services.
Visit hijacking: Using the PUT endpoint, I changed the member_id on the visit from Member B to Member A, then back to Member B. The attacker can bounce visits between arbitrary members. I also changed the status to completed, injecting a false completion record with a timestamp into the victim's health history.
Care record access: After marking the visit as completed, I generated a signed care record URL using the visit ID. The signed URL bypasses Bearer token authentication, only the signature is needed to access the PDF. While a pending visit doesn't have a clinical care record (that requires a provider to actually join), the attack chain is complete if a provider accepts the session.
The Proof
Every other member endpoint on the platform properly returned 403 for cross-account access. Only the visit creation and modification endpoints were missing the authorization check. The control test confirmed the platform knows how to enforce ownership, it just wasn't applied to these two endpoints.
Impact
- Create telehealth visits for any member, notifying real providers and consuming session slots
- Block victims from scheduling their own visits (denial of healthcare)
- Reassign visits between members and inject false completion records into health histories
- Generate signed care record URLs that bypass token authentication
Timeline
Reported and triaged within a week. The team validated the authorization bypass and confirmed the security impact. Rated High severity and sent to engineering for remediation.
Takeaway
When an API accepts a resource ID in the request body (like member_id), always check whether the server verifies ownership against the authenticated user. In this case, the platform had proper authorization on read endpoints but skipped it on write endpoints. The write side is where the real damage happens: creating records, changing states, and triggering downstream actions like provider notifications. On healthcare platforms, unauthorized write access to visit records has regulatory implications under HIPAA.