Summary
OpenEMR's controller dispatcher can allow authenticated users to invoke controllers that are missing from its access-control map, without enforcing the expected permissions. A low-privilege user may therefore access administrative actions, including changing insurance-routing settings or viewing patient information.
OpenEMR's controller dispatcher can allow authenticated users to invoke controllers that are missing from its access-control map, without enforcing the expected permissions. A low-privilege user may therefore access administrative actions, including changing insurance-routing settings or viewing patient information.
Affected context
The issue affects OpenEMR's controller dispatch and authorization checks in library/classes/Controller.class.php. When a controller is not represented in CONTROLLER_ACL_MAP, the ACL check returns without enforcing a permission requirement. This can expose actions intended to be reached only through permission-gated routes, including insurance-partner and patient-finder actions.
The issue affects OpenEMR's controller dispatch and authorization checks in library/classes/Controller.class.php. When a controller is not represented in CONTROLLER_ACL_MAP, the ACL check returns without enforcing a permission requirement. This can expose actions intended to be reached only through permission-gated routes, including insurance-partner and patient-finder actions.
Exploit preconditions
- Attack surface: OpenEMR controller dispatch
- Required access: An authenticated account with low privileges
- Trigger point: Direct invocation of an action on a controller missing from
CONTROLLER_ACL_MAP - Why exploitation is possible: The authorization check fails open for unmapped controllers instead of denying access or requiring an explicit permission
- Attack surface: OpenEMR controller dispatch
- Required access: An authenticated account with low privileges
- Trigger point: Direct invocation of an action on a controller missing from
CONTROLLER_ACL_MAP - Why exploitation is possible: The authorization check fails open for unmapped controllers instead of denying access or requiring an explicit permission
Why this happens
The dispatcher does not require every controller to have an explicit authorization policy. When an entry is absent from CONTROLLER_ACL_MAP, checkControllerAcl() returns without enforcing access control, allowing the action to proceed. This is a missing authorization flaw mapped to CWE-862: Missing Authorization.
The dispatcher does not require every controller to have an explicit authorization policy. When an entry is absent from CONTROLLER_ACL_MAP, checkControllerAcl() returns without enforcing access control, allowing the action to proceed. This is a missing authorization flaw mapped to CWE-862: Missing Authorization.
Potential impact
- An unauthorized user could create or alter insurance-routing hosts and credentials.
- An unauthorized user could enumerate patient names, dates of birth, and identifiers.
- Other administrative controller actions could be exposed if they rely on routes with ACL checks but are reachable through the dispatcher.
- Changes to insurance-routing settings could disrupt or redirect related workflows.
- An unauthorized user could create or alter insurance-routing hosts and credentials.
- An unauthorized user could enumerate patient names, dates of birth, and identifiers.
- Other administrative controller actions could be exposed if they rely on routes with ACL checks but are reachable through the dispatcher.
- Changes to insurance-routing settings could disrupt or redirect related workflows.
General mitigation guidance
Defensive patterns for this class of issue include:
- Denying access by default when a controller or action has no explicit authorization policy.
- Applying authorization checks consistently at the action or controller boundary, not only through selected routes.
- Maintaining a complete, centrally enforced mapping between controller actions and required permissions.
- Limiting accounts to the minimum privileges needed and reviewing sensitive actions for appropriate role checks.
- Treating direct controller dispatch as an untrusted entry point and validating authorization before performing sensitive operations.
Defensive patterns for this class of issue include:
- Denying access by default when a controller or action has no explicit authorization policy.
- Applying authorization checks consistently at the action or controller boundary, not only through selected routes.
- Maintaining a complete, centrally enforced mapping between controller actions and required permissions.
- Limiting accounts to the minimum privileges needed and reviewing sensitive actions for appropriate role checks.
- Treating direct controller dispatch as an untrusted entry point and validating authorization before performing sensitive operations.
How teams detect issues like this
- Use static analysis or targeted searches to identify dispatch paths where missing ACL entries result in an allow or early return.
- Review all controller actions that modify configuration, access patient data, or perform administrative operations, and verify each has an explicit permission check.
- Test authorization behavior for direct action invocation as well as normal UI or route-based access.
- Enforce CI or policy checks that flag newly added controllers or actions without corresponding authorization rules.
- Review access logs for low-privilege accounts invoking sensitive controller actions.
- Use static analysis or targeted searches to identify dispatch paths where missing ACL entries result in an allow or early return.
- Review all controller actions that modify configuration, access patient data, or perform administrative operations, and verify each has an explicit permission check.
- Test authorization behavior for direct action invocation as well as normal UI or route-based access.
- Enforce CI or policy checks that flag newly added controllers or actions without corresponding authorization rules.
- Review access logs for low-privilege accounts invoking sensitive controller actions.

