Repository: frappe/frappe

Issue:
bug: CRITICAL Security Issue In Frappe/ERPNext
nothing to see here


Discussion:
@rmehta @nabinhait  sorry to tag people on the issue but i see no traction on this issue. This is a problem on any frappe/erpnext instance out there. If someone writes a script to spam a frappe/erpnext server they can.
maybe instead of posting a security issue in the open you could've reported it to us at https://erpnext.com/security, that would have made us look at it faster.

and now since you have posted it in the public, I hope you know the implications of it. please raise this issue on the url I've specified above and we'll take a look at it.
@Thunderbottom What do you think I did? I posted it there first 4-5 days ago. This makes it clear you are not checking that too.
@govindsmenokee we've seen it already. we have a lot of other things to look at too and we try to prioritize everything. sometimes it takes us time to get back to the reported issues. the current comments implementation is more of a design problem than a security issue.

we'll get it solved, please be patient; a team so small can only do so much at once. and being an open source software maybe even you or anyone from the community can contribute towards fixing this issue if you think this is high priority. I hope that is understandable.
@Thunderbottom Ok this contradicts what you said in the previous comment as to not raising the issue at https://erpnext.com/security Please avoid any sort of accusations. Im only trying to help out here. If help is not required please make that clear. I also have N number of things to do. I could just make the fix at my fork and sleep peacefully.
@Thunderbottom  Also if there was at least an acknowledgement to the security vulnerability issue raised then I would not have posted an issue here. Also security flaws are just a subset of bad design decisions only. So for me at least it doesn't make sense when you call it design issue.
firstly, you posted a security issue in the open. that too within a couple of days of reporting it on the security portal.

secondly, nobody's blaming you. all i stated is that you can contribute to the project and fix this issue if you feel it is of high priority to you. right now we have an influx of other things to look into, and not everything can be done at once. nobody's asking you to not help, nobody's saying we won't fix it. but with the sort of expectation you have, you seem to want the issue to be fixed instantly. again, as a team of 20 developers there's only so much we can focus into at once. you are free to fix the issues yourself and open a pull request for it, or as you said you may "fix it on your fork and sleep over it peacefully". nobody's stopping you from doing that. it's just that you have set your expectations wrong from something that is free and open source. if you only rely on the developers to fix the problems and expect things to come to you for free and at the time that you want, then i'll suggest that you maybe try and run a project by yourself. i hope you understand the reason for open source is "open community contributions" and not "free expectations".

i agree, the acknowledgement system was broken up until a few days ago, and we do have an acknowledgement system in place right now. but that in no way warrants you to still be raising a security issue out in the open. i hope that is understandable.
@Thunderbottom I have no sorts of expectation from any one from frappe/erpnext or the community. Im not relying on frappe/erpnext team to complete a feature request that I raised. 

1. I found a problem that could potentially compromise the data integrity of the system.
2. Tried reporting it to the team through the security report program.
3. Did not get a response or an acknowledgement.
4. I did not have any other means to know whether you guys are aware of this issue.

Now coming to the part where you said "fix this issue if you feel it is of high priority to you" Im just surprised because if I were part of a project or a team that is owning a product be it open/closed source would feel the need to fix this issue and give it at most priority as all systems are affected by this issue. Im no one to take decisions on behalf of frappe/erpnext but just saying that the fundamental grounds on which any human being would prioritise stuff is just beaten to the ground with that statement.

Any how I apologise for posting the "Design Issue" out in the open.

Also please feel free to fix this issue whenever you feel is the right time. I want to iterate that I'm not expecting any solution for this issue from the frappe/erpnext team.
> give it at most priority as all systems are affected by this issue.

you still can. nobody's saying you can't do it just because we aren't taking it up on priority.

> Im no one to take decisions on behalf of frappe/erpnext but just saying that the fundamental grounds on which any human being would prioritise stuff is just beaten to the ground with that statement.

fundamentally speaking, i assume you are perfectly capable of fixing this issue for yourself. if i may quote you from before:

> I also have N number of things to do. I could just make the fix at my fork and sleep peacefully.

then why not fix it yourself and open a pull request on the framework? why wait for the developers to do it for you?

there are people who have fixed "design issues" before, all by themselves. we consider them a part of the community and are really grateful for their contributions towards the project. what you have is nothing short of an expectation, even if you do not agree to it. if you still feel the priority is pretty high for this vulnerability, please feel free to actually contribute towards it.

this is not a closed source project, contributions are most welcome.
> what you have is nothing short of an expectation, even if you do not agree to it

I mean if you have it already figured out as to what I'm expecting or not expecting, You can go ahead and be in that state of denial.
If a paid customer raises this issue, It will automatically become priority for you. I hope at least in that case it does. If not i just pray for the frappe/erpnext cloud users.
sure, we're all thankful for your well wishes.
(https://discuss.erpnext.com/t/stored-xss-in-erpnext-demo-website/36587) this was one instance where the issue was reported out in the public and was handled in a graceful manner. It's not about how long it will take for you to fix or who is fixing it. It is the attitude to acknowledge that there is problem rather than defending or being totally arrogant about it.
> It is the attitude to acknowledge that there is problem rather than defending or being totally arrogant about it.

again, i cannot stress enough on how you can fix things for yourself if you think this issue matters a lot to you. there was absolutely no need to post it in public in the first place. either wait for the issue to be fixed, or go ahead and fix it yourself.

also i hope you see the irony in posting a security issue in public, and then defending yourself over it by complacently posting an unrelated security issue from over two years ago. speaks volumes about being defensive.
@Thunderbottom OH! MY BAD THAT WAS A DIFFERENT SECURITY ISSUE ALTOGETHER. Thank you for pointing it out. I thought it was the same issue reported 2 years ago and you still haven't given any importance/priority to it.
I hope you were able to sense the sarcasm in that 😂

Resolving patch:
diff --git a/frappe/templates/includes/comments/comments.py b/frappe/templates/includes/comments/comments.py
--- a/frappe/templates/includes/comments/comments.py
+++ b/frappe/templates/includes/comments/comments.py
@@ -3,29 +3,44 @@
 from __future__ import unicode_literals
 
 import frappe
-import frappe.utils
+import re
 from frappe.website.render import clear_cache
+from frappe.utils import add_to_date, now
 
 from frappe import _
 
-@frappe.whitelist(allow_guest=True)
+@frappe.whitelist()
 def add_comment(comment, comment_email, comment_by, reference_doctype, reference_name, route):
 	doc = frappe.get_doc(reference_doctype, reference_name)
 
-	if len(comment) < 10:
-		frappe.msgprint(_('Comment Should be atleast 10 characters'))
-		return ''
+	if not comment.strip():
+		frappe.msgprint(_('The comment cannot be empty'))
+		return False
 
-	blacklist = ['http://', 'https://', '@gmail.com']
+	url_regex = re.compile(r"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+", re.IGNORECASE)
+	email_regex = re.compile(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", re.IGNORECASE)
 
-	if any([b in comment for b in blacklist]):
+	if url_regex.search(comment) or email_regex.search(comment):
 		frappe.msgprint(_('Comments cannot have links or email addresses'))
-		return ''
+		return False
+
+	if not comment_email == frappe.session.user:
+		comment_email = frappe.session.user
+
+	comments_count = frappe.db.count("Comment", {
+		"comment_type": "Comment",
+		"comment_email": frappe.session.user,
+		"creation": (">", add_to_date(now(), hours=-1))
+	})
+
+	if comments_count > 20:
+		frappe.msgprint(_('Hourly comment limit reached for: {0}').format(frappe.bold(frappe.session.user)))
+		return False
 
 	comment = doc.add_comment(
-		text = comment,
-		comment_email = comment_email,
-		comment_by = comment_by)
+		text=comment,
+		comment_email=comment_email,
+		comment_by=comment_by)
 
 	comment.db_set('published', 1)
 
@@ -40,18 +55,13 @@ def add_comment(comment, comment_email, comment_by, reference_doctype, reference
 
 	# notify creator
 	frappe.sendmail(
-		recipients = frappe.db.get_value('User', doc.owner, 'email') or doc.owner,
-		subject = _('New Comment on {0}: {1}').format(doc.doctype, doc.name),
-		message = content,
+		recipients=frappe.db.get_value('User', doc.owner, 'email') or doc.owner,
+		subject=_('New Comment on {0}: {1}').format(doc.doctype, doc.name),
+		message=content,
 		reference_doctype=doc.doctype,
 		reference_name=doc.name
 	)
 
-	if comment.published:
-		# revert with template if all clear (no backlinks)
-		template = frappe.get_template("templates/includes/comments/comment.html")
-
-		return template.render({"comment": comment.as_dict()})
-
-	else:
-		return ''
+	# revert with template if all clear (no backlinks)
+	template = frappe.get_template("templates/includes/comments/comment.html")
+	return template.render({"comment": comment.as_dict()})
diff --git a/frappe/website/doctype/web_form/web_form.py b/frappe/website/doctype/web_form/web_form.py
--- a/frappe/website/doctype/web_form/web_form.py
+++ b/frappe/website/doctype/web_form/web_form.py
@@ -122,10 +122,6 @@ def get_context(self, context):
 		'''Build context to render the `web_form.html` template'''
 		self.set_web_form_module()
 
-		context._login_required = False
-		if self.login_required and frappe.session.user == "Guest":
-			context._login_required = True
-
 		doc, delimeter = make_route_string(frappe.form_dict)
 		context.doc = doc
 		context.delimeter = delimeter
@@ -142,7 +138,7 @@ def get_context(self, context):
 		if self.is_standard:
 			self.use_meta_fields()
 
-		if not context._login_required:
+		if not frappe.session.user == "Guest":
 			if self.allow_edit:
 				if self.allow_multiple:
 					if not frappe.form_dict.name and not frappe.form_dict.new:


Test patch: