CVE-2026-33931 Overview
CVE-2026-33931 is an Insecure Direct Object Reference (IDOR) vulnerability affecting OpenEMR, a widely-used free and open source electronic health records (EHR) and medical practice management application. The vulnerability exists in the patient portal payment page (portal/portal_payment.php) where authenticated portal patients can access other patients' payment records by manipulating the recid query parameter. This flaw exposes sensitive Protected Health Information (PHI), including invoice/billing data and payment card metadata, to unauthorized access.
Critical Impact
Authenticated patients can access other patients' billing records and payment card metadata through parameter manipulation, exposing PHI and potentially violating HIPAA compliance requirements.
Affected Products
- OpenEMR versions prior to 8.0.0.3
- OpenEMR Patient Portal Payment Module (portal/portal_payment.php)
- OpenEMR Portal Audit Record System (portal/lib/appsql.class.php)
Discovery Timeline
- 2026-03-26 - CVE CVE-2026-33931 published to NVD
- 2026-03-26 - Last updated in NVD database
Technical Details for CVE-2026-33931
Vulnerability Analysis
This IDOR vulnerability stems from a fundamental authorization flaw in OpenEMR's patient portal payment functionality. The application fails to validate that the authenticated user requesting a payment record is actually the owner of that record. When a patient accesses the payment page, the system retrieves records based solely on the recid parameter without verifying that the record belongs to the requesting patient's session.
The impact of this vulnerability is significant in healthcare environments where patient financial and billing information is considered PHI under HIPAA regulations. An attacker with a valid patient portal account can systematically enumerate other patients' payment records, potentially exposing:
- Patient billing information and invoice details
- Payment card metadata (partial card numbers, expiration dates)
- Patient identification information linked to financial records
Root Cause
The root cause lies in the getPortalAuditRec() function within portal/lib/appsql.class.php. The original implementation accepts a recid parameter and queries the onsite_portal_activity table without any patient ownership validation. The SQL query retrieves records based solely on the record ID, allowing any authenticated user to access any record by simply knowing or guessing the ID value.
Attack Vector
The attack is network-based and requires low privileges (valid patient portal authentication). An attacker who has registered as a patient or compromised a patient account can:
- Authenticate to the OpenEMR patient portal
- Navigate to the payment page at portal/portal_payment.php
- Observe the recid parameter in the URL
- Modify the recid value to other sequential or guessed IDs
- Access payment records belonging to other patients
The following patch demonstrates the security fix applied in version 8.0.0.3:
- public function getPortalAuditRec($recid)
+ public function getPortalAuditRec($recid, $patientId = null)
{
$return = false;
$result = false;
try {
- $sql = "Select * From onsite_portal_activity Where id = ?";
- $return = sqlStatementNoLog($sql, $recid);
+ if ($patientId !== null) {
+ $sql = "Select * From onsite_portal_activity Where id = ? And patient_id = ?";
+ $return = sqlStatementNoLog($sql, [$recid, $patientId]);
+ } else {
+ $sql = "Select * From onsite_portal_activity Where id = ?";
+ $return = sqlStatementNoLog($sql, $recid);
+ }
$result = true;
} catch (Exception $e) {
$this->errorHandler($e, $sql);
Source: GitHub Commit 7bf30e0
Detection Methods for CVE-2026-33931
Indicators of Compromise
- Unusual access patterns to portal/portal_payment.php with varying recid values from the same session
- Sequential or bulk requests to the payment endpoint with incrementing record IDs
- Access log entries showing patients viewing records with IDs not associated with their patient profile
- Anomalous spikes in portal activity audit table queries
Detection Strategies
- Implement web application firewall (WAF) rules to detect parameter enumeration attempts on the recid parameter
- Configure application logging to capture and alert on mismatched patient ID to record ID access attempts
- Deploy network monitoring to identify unusual request patterns targeting the patient portal payment endpoint
- Review OpenEMR access logs for sequential recid parameter values from single user sessions
Monitoring Recommendations
- Enable detailed audit logging for all patient portal payment page access
- Implement real-time alerting for access attempts where the requested record's patient_id does not match the authenticated user
- Monitor for automated scanning tools or scripts targeting the payment endpoint
- Establish baseline metrics for normal patient portal usage to identify anomalous access patterns
How to Mitigate CVE-2026-33931
Immediate Actions Required
- Upgrade OpenEMR to version 8.0.0.3 or later immediately
- Review access logs for any evidence of exploitation prior to patching
- Audit patient portal activity for unauthorized record access
- Notify affected patients if evidence of data exposure is found (HIPAA Breach Notification requirements may apply)
Patch Information
OpenEMR has released version 8.0.0.3 which patches this vulnerability. The fix adds a patientId parameter to the getPortalAuditRec() function and includes the patient ID in the SQL WHERE clause, ensuring records can only be retrieved when the authenticated patient's ID matches the record's owner. The patch is available in the GitHub Release v8.0.0.3. Additional details are available in the GitHub Security Advisory GHSA-hf37-5rp9-j27j.
Workarounds
- Restrict access to the patient portal payment functionality at the web server level until the patch is applied
- Implement additional authentication checks at the network or reverse proxy layer for the /portal/portal_payment.php endpoint
- Deploy WAF rules to block requests with modified recid parameters that don't match session context
- Temporarily disable the patient portal payment feature if immediate patching is not possible
# Apache configuration to restrict access to payment page (temporary workaround)
<Location "/portal/portal_payment.php">
# Require additional IP-based restrictions or disable endpoint
Require ip 127.0.0.1
# Or deny all access temporarily
# Require all denied
</Location>
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

