CVE-2026-50026
Description
Frappe framework prior to 15.107.0 and 16.17.0 lacks permission checks in relink and set_email_password endpoints, allowing unauthorized resource access.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Frappe framework prior to 15.107.0 and 16.17.0 lacks permission checks in relink and set_email_password endpoints, allowing unauthorized resource access.
Vulnerability
Frappe framework versions before 15.107.0 (for the 15.x series) and before 16.17.0 (for the 16.x series) contain a vulnerability in the relink and set_email_password endpoints. These endpoints lack proper permission checks, making them accessible without authorization. The issue is present in all versions prior to the patched releases [1].
Exploitation
An attacker with network access to a vulnerable Frappe instance can exploit this by sending crafted HTTP requests to the relink or set_email_password endpoints. No authentication or special privileges are required. The attacker can directly access resources that should be protected [1].
Impact
Successful exploitation allows an attacker to gain unauthorized access to resources within the Frappe application. This could lead to information disclosure, modification of data, or other actions depending on the nature of the exposed resources. The exact impact is limited to the permissions that are missing [1].
Mitigation
The vulnerability has been patched in Frappe framework versions 15.107.0 and 16.17.0. Users should update to these or later versions immediately. No workarounds are available; updating is the only remediation [1].
AI Insight generated on Jun 12, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2Patches
4205cdc7d67d0fix: add perm check on user email awaiting
1 file changed · +4 −1
frappe/core/doctype/user/user.py+4 −1 modified@@ -1035,7 +1035,10 @@ def has_email_account(email: str): @frappe.whitelist(allow_guest=False) -def get_email_awaiting(user): +def get_email_awaiting(user: str): + if user != frappe.session.user: + frappe.has_permission("User", "read", doc=user, throw=True) + return frappe.get_all( "User Email", fields=["email_account", "email_id"],
6b98d8700f38fix: check permissions for getting and updating events
1 file changed · +16 −5
frappe/desk/doctype/event/event.py+16 −5 modified@@ -237,8 +237,15 @@ def remove_event_from_user_settings(self): @frappe.whitelist() def update_attending_status(event_name, attendee, status): event_doc = frappe.get_doc("Event", event_name) + caller = frappe.session.user - if event_doc.owner == attendee == frappe.session.user: + if attendee != caller: + if event_doc.owner != caller and not frappe.has_permission("Event", "write", event_name): + frappe.throw( + _("You are not allowed to update attendance for another user."), frappe.PermissionError + ) + + if event_doc.owner == caller: frappe.db.set_value("Event", event_name, "attending", status) return @@ -247,8 +254,7 @@ def update_attending_status(event_name, attendee, status): frappe.db.set_value("Event Participants", participant.name, "attending", status) return - if not has_permission(event_doc, user=attendee): - frappe.throw(_("You are not allowed to update the status of this event.")) + frappe.throw(_("Attendee not found in this event.")) @frappe.whitelist() @@ -334,7 +340,12 @@ def send_event_digest(): def get_events( start: date, end: date, user: str | None = None, for_reminder: bool = False, filters=None ) -> list[frappe._dict]: - user = user or frappe.session.user + caller = frappe.session.user + target_user = user or caller + + if user and user != caller: + if not frappe.has_permission("Event", ptype="read"): + frappe.throw(_("You are not allowed to view events for another user."), frappe.PermissionError) type EventLikeDict = Event | frappe._dict resolved_events: list[EventLikeDict] = [] @@ -406,7 +417,7 @@ def get_events( { "start": start, "end": end, - "user": user, + "user": target_user, }, as_dict=True, )
0f68f9f993e3fix(client): add blocklist for save endpoint
1 file changed · +5 −0
frappe/client.py+5 −0 modified@@ -236,6 +236,11 @@ def save(doc): if isinstance(doc, str): doc = json.loads(doc) + forbidden = {"docstatus", "idx"} + for field in doc: + if field in forbidden: + frappe.throw(_("Cannot edit standard fields")) + doc = frappe.get_doc(doc) doc.save()
0fe914732ed2chore(release): Bumped to Version 15.107.0
1 file changed · +1 −1
frappe/__init__.py+1 −1 modified@@ -51,7 +51,7 @@ ) from .utils.lazy_loader import lazy_import -__version__ = "15.106.0" +__version__ = "15.107.0" __title__ = "Frappe Framework" # This if block is never executed when running the code. It is only used for
Vulnerability mechanics
Root cause
"Missing permission checks on whitelisted endpoints allow unauthorized access to user email accounts, event data, and protected document fields."
Attack vector
An authenticated attacker can call the `get_email_awaiting` endpoint with another user's name to read that user's email account mappings [patch_id=5723718]. The `update_attending_status` and `get_events` endpoints can be invoked with arbitrary `attendee` or `user` parameters to modify or view events belonging to other users [patch_id=5723719]. The `save` endpoint can be called with a document payload containing `docstatus` or `idx` to bypass workflow state restrictions [patch_id=5723717]. All three attack vectors require only a valid Frappe session and no special privileges.
Affected code
The patches address four distinct authorization gaps. `get_email_awaiting` in `frappe/core/doctype/user/user.py` lacked a permission check before returning another user's email accounts [patch_id=5723718]. `update_attending_status` and `get_events` in `frappe/desk/doctype/event/event.py` did not verify that the caller had permission to modify or view events for other users [patch_id=5723719]. The `save` endpoint in `frappe/client.py` allowed editing protected fields such as `docstatus` and `idx` [patch_id=5723717].
What the fix does
Patch 5723718 adds a permission check in `get_email_awaiting`: if the requested user differs from the session user, it calls `frappe.has_permission("User", "read", doc=user, throw=True)` to enforce read access. Patch 5723719 adds similar guards in `update_attending_status` and `get_events` — the caller must either be the event owner or have write permission on the event to update another attendee's status, and must have read permission on the Event doctype to view another user's events. Patch 5723717 introduces a blocklist (`{"docstatus", "idx"}`) in the `save` endpoint that rejects any document payload containing those fields before the document is saved.
Preconditions
- authValid Frappe session (authenticated user).
- networkNetwork access to the Frappe application endpoints.
- inputKnowledge of another user's name (for email/event attacks) or ability to craft a document payload with forbidden fields.
Generated on Jun 12, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
1News mentions
0No linked articles in our index yet.