Entry, Escalation, Persistence: Taking Apart Frappe's Document Follow | Robin Roy
Entry, Escalation, Persistence: Taking Apart Frappe's Document Follow
02 Aug, 2026
Frappe is an open-source framework used to build software like ERPNext, a widely deployed open-source ERP. My job is mostly working with apps built on this framework. During one session in May I noticed some peculiarities with how frappe’s document follow feature is implemented. Curious, I dug deep to find a chain of three authorization failures - one at the object level, one at the field level, and one in the lifetime of the grant itself - that allowed an attacker to access data they aren’t authorized to.
The frappe team promptly acknowledged the vulnerabilities and started work on it. The vulnerability chain was patched and labeled CVE-2026-66000, CVE-2026-66058, and CVE-2026-66059.
Timeline:
May 27 2026 8:10 PM IST - Issue filed to frappe team
May 27 2026 9:00 PM IST - Issue acknowledged
Jun 8 2026 1:25 PM IST - Pull Request opened with the fixes by Aarol D’Souza and me.
Jun 16 2026 10:09 PM IST - Frappe v16.23.0 ships with the fix.
Jun 16 2026 10:18 PM IST - Frappe v15.112.0 ships with the fix.
Jul 30 2026 10:50 AM IST - The 3 vulnerabilities were officially published as security advisories.
Ok now with that out of the way, let us start by figuring out what frappe document follow even is.
What is document follow?
It’s funny how I’m seeing this message now while writing the blog. The feature is slated to deprecate on v17.
If you’re used to ERP/CRM systems, you must’ve encountered this feature before in slightly different forms: Salesforce calls it following records, and Microsoft Dynamics 365 has its own equivalent. Every system that grows past a handful of users eventually develops this feature, because it’s the obvious answer to an obvious question: how do I find out when this thing changes without opening it every morning?
Frappe’s answer is Document Follow. You open a document - an Employee record, a Sales Order, an Opportunity, whatever - hit follow, and Frappe emails you when it changes. That’s it. That’s the whole feature.
But now if you look inside the button, fundamentally it is a feature that says: this user should be informed about the changes to this document<br>In Frappe, a DocType is the name of the database table. Documents are rows in those tables. For example, there’ll be a database table called Leads, each lead (document) is then a row in that table. Keep this in mind to avoid confusion when I say document / DocType.
, on an ongoing basis, by email. It’s a standing subscription to a document’s data.
Once you say it that way, three questions ask themselves:
Who’s allowed to create one of those rows?
What exactly goes into the email?
What happens to the row when the user’s access changes?
This post is about each of them, in that order.
So who’s allowed to follow a document?
Any authenticated system user<br>A system user is anyone who can access the Desk view. Desk view in frappe means the low-code backend UI. Any user with a role is automatically a system user.
with document follow enabled from their user settings. The doctype should also support version tracking. And that is our entry vulnerability aka CVE-2026-66058. The reason for this was the lack of an access control check, the server forgot to ask whether the client is actually authorized to access this document.
Request
curl -X POST "https:///api/method/frappe.desk.form.document_follow.update_follow" \<br>-H "Content-Type: application/json" \<br>-H "Cookie: sid=" \<br>-H "X-Frappe-CSRF-Token: " \<br>--data '{<br>"doctype": "Employee",<br>"doc_name": "EMP-XXXXX",<br>"following": true<br>}'
Response
"message": true,<br>"_server_messages": "[\"{\\\"message\\\":\\\"Following document \\\",\\\"as_table\\\":false,\\\"title\\\":\\\"Message\\\",\\\"alert\\\":1}\"]"
The fix is a simple 2-liner.
if not frappe.has_permission(doctype, "read", doc=doc_name, user=user):<br>frappe.throw(_("You do not have permission to access this document."), frappe.PermissionError)
So this meant any user could follow any arbitrary document with Track Changes enabled<br>Sensitive doctypes like Employee from ERPNext, most of HR and Payroll Doctypes from HRMS ship with this enabled by default
, no matter how sensitive, and get updates siphoned to them regularly.
So what exactly goes into the email?
A document with permission only for System Manager<br>System Manager is the superuser.
We followed it regardless, and this is the email received when a change happens.
So once the document gets an update, the diff is logged in a Version table and then a parser is used to make a good looking email from it to send to the client. This is where the second vulnerability lives. It is just a bug if all you can do is follow arbitrary documents; it becomes a vulnerability when the data actually is shared. And that is...