FELG Dent Healthcare Breach: IDOR API Flaw Exposes 2.4 Million Patient Records
On October 1, 2026, Polish dental software company FELG Software confirmed that its flagship cloud practice management software, FELG Dent, was compromised in a major cyberattack. Threat actor "Horus" extracted sensitive records belonging to over 2.4 million dental patients and 16,000 dental clinics. The breach was made possible by a fundamental Insecure Direct Object Reference (IDOR) flaw in the platform's multi-tenant REST API.
Anatomy of the IDOR / BOLA Vulnerability
The attacker registered a standard low-cost demo account on the FELG Dent cloud portal. While inspecting HTTP traffic during application use, the attacker identified that patient management endpoints relied on predictable sequential integer identifiers without verifying whether the requesting user's practice possessed ownership of the record:
GET /api/v2/clinics/demo_account/patients/849201 HTTP/1.1
Host: cloud.felgdent.pl
Authorization: Bearer [Valid Demo Account Token]
HTTP/1.1 200 OK
Content-Type: application/json
{
"patient_id": 849201,
"clinic_id": 1042,
"first_name": "Jan",
"last_name": "Kowalski",
"pesel": "85031201948",
"address": "ul. Marszalkowska 12, Warszawa",
"phone": "+48 501 234 567",
"prescriptions": [
{ "id": 10294, "drug": "Amoxicillin 500mg", "date": "2026-09-15" }
],
"medical_history": "Type 2 Diabetes, Penicillin Allergy"
}
Because the backend database query simply executed SELECT * FROM patients WHERE id = :patient_id without validating clinic_id == current_user.clinic_id, the attacker automated a script to iterate patient_id values from 1 to 3,000,000. Over several days, 2.4 million patient dossiers and 1.2 million prescriptions were systematically exfiltrated.
API Flaw Breakdown: The Missing Authorization Gate
Attacker (Demo Account Token)
│
├──► GET /api/v2/patients/{id} (Iterating id = 1, 2, 3...)
│
├──► [API Gateway]: Token is valid! Request dispatched to backend.
│
▼
[Backend Application Service]
│
├──► Flawed Query: SELECT * FROM patients WHERE id = ?
│ (Missing: AND tenant_id = req.user.tenant_id)
│
▼
Unrestricted Multi-Tenant Data Exfiltration Across 16,000 Clinics!
Regulatory & Remediation Guidance
- Replace Sequential Identifiers with UUIDv4: Migrate database primary keys away from sequential auto-incrementing integers to cryptographically secure UUIDv4 identifiers, mitigating enumeration risks.
- Implement Behavioral API Rate Limiting: Configure API gateways to alert and throttle clients requesting large volumes of distinct object IDs within short time windows.
Enforce Object-Level Authorization Filters: Implement centralized policy enforcement (such as ABAC or Open Policy Agent) requiring all database retrieval operations to assert tenant context:
# Example secure query pattern in Python/SQLAlchemy
patient = db.session.query(Patient).filter(
Patient.id == patient_id,
Patient.clinic_id == current_user.clinic_id # Mandatory tenant scoping!
).first_or_404()