VYPR
High severity8.8NVD Advisory· Published Aug 18, 2017· Updated May 13, 2026

CVE-2015-5081

CVE-2015-5081

Description

Cross-site request forgery (CSRF) vulnerability in django CMS before 3.0.14, 3.1.x before 3.1.1 allows remote attackers to manipulate privileged users into performing unknown actions via unspecified vectors.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
django-cmsPyPI
< 3.0.143.0.14
django-cmsPyPI
>= 3.1.0b1, < 3.1.13.1.1

Affected products

2
  • cpe:2.3:a:django-cms:django_cms:*:*:*:*:*:*:*:*+ 1 more
    • cpe:2.3:a:django-cms:django_cms:*:*:*:*:*:*:*:*range: <=3.0.13
    • cpe:2.3:a:django-cms:django_cms:3.1:*:*:*:*:*:*:*

Patches

2
f77cbc607d6e

Merge pull request #4218 from divio/issues/merge_csrf_fix

https://github.com/django-cms/django-cmsIacopo SpallettiJun 27, 2015via ghsa
7 files changed · +51 12
  • cms/admin/pageadmin.py+6 0 modified
    @@ -928,6 +928,7 @@ def change_template(self, request, object_id):
                 helpers.make_revision_with_plugins(page, request.user, message)
             return HttpResponse(force_unicode(_("The template was successfully changed")))
     
    +    @require_POST
         @wrap_transaction
         def move_page(self, request, page_id, extra_context=None):
             """
    @@ -1013,6 +1014,7 @@ def copy_language(self, request, page_id):
                     helpers.make_revision_with_plugins(page, request.user, message)
                 return HttpResponse("ok")
     
    +    @require_POST
         @wrap_transaction
         def copy_page(self, request, page_id, extra_context=None):
             """
    @@ -1046,6 +1048,7 @@ def copy_page(self, request, page_id, extra_context=None):
             context.update(extra_context or {})
             return HttpResponseRedirect('../../')
     
    +    @require_POST
         @wrap_transaction
         @create_revision()
         def publish_page(self, request, page_id, language):
    @@ -1146,6 +1149,7 @@ def cleanup_history(self, page, publish=False):
                             revision.delete()
                             deleted.append(revision.pk)
     
    +    @require_POST
         @wrap_transaction
         def unpublish(self, request, page_id, language):
             """
    @@ -1181,6 +1185,7 @@ def unpublish(self, request, page_id, language):
                 path = "%s?language=%s&page_id=%s" % (path, request.GET.get('redirect_language'), request.GET.get('redirect_page_id'))
             return HttpResponseRedirect(path)
     
    +    @require_POST
         @wrap_transaction
         def revert_page(self, request, page_id, language):
             page = get_object_or_404(Page, id=page_id)
    @@ -1316,6 +1321,7 @@ def preview_page(self, request, object_id, language):
                 page.site.domain, url)
             return HttpResponseRedirect(url)
     
    +    @require_POST
         def change_innavigation(self, request, page_id):
             """
             Switch the in_navigation of a page
    
  • cms/static/cms/js/modules/cms.changelist.js+11 2 modified
    @@ -180,8 +180,17 @@ $(document).ready(function () {
     				// cancel if not confirmed
     				if(!confirm(that.options.lang.publish.replace('§', $(this).text().toLowerCase()))) return false;
     
    -				// publish page and update
    -				window.location.href = $(this).attr('href');
    +				// send post request to prevent xss attacks
    +				$.ajax({
    +					'type': 'post',
    +					'url': $(this).prop('href'),
    +					'success': function () {
    +						CMS.API.Helpers.reloadBrowser();
    +					},
    +					'error': function (request) {
    +						throw new Error(request);
    +					}
    +				});
     			});
     		},
     
    
  • cms/static/cms/js/modules/cms.toolbar.js+21 1 modified
    @@ -213,7 +213,27 @@ $(document).ready(function () {
     
     				// in case of the publish button
     				btn.find('.cms_publish-page').bind(that.click, function (e) {
    -					if(!confirm(that.config.lang.publish)) e.preventDefault();
    +					if(!confirm(that.config.lang.publish)) {
    +						e.preventDefault();
    +					}
    +				});
    +
    +				btn.find('.cms_btn-publish').bind(that.click, function (e) {
    +					e.preventDefault();
    +					// send post request to prevent xss attacks
    +					$.ajax({
    +						'type': 'post',
    +						'url': $(this).prop('href'),
    +						'data': {
    +							'csrfmiddlewaretoken': CMS.config.csrf
    +						},
    +						'success': function () {
    +							CMS.API.Helpers.reloadBrowser();
    +						},
    +						'error': function (request) {
    +							throw new Error(request);
    +						}
    +					});
     				});
     			});
     		},
    
  • cms/templates/admin/cms/page/tree/menu_item.html+2 2 modified
    @@ -30,8 +30,8 @@
     				{% if lang in page.languages %}
     				<div class="language-tooltip" hidden="hidden">
     					{% trans "Pick an action:" %}
    -					<a href="./{{ page.id }}/{{ lang }}/unpublish/?redirect_language={{ preview_language }}&redirect_page_id={{ request.GET.page_id }}">{% trans "Unpublish" %}</a>
    -					<a href="./{{ page.id }}/{{ lang }}/publish/?redirect_language={{ preview_language }}&redirect_page_id={{ request.GET.page_id }}">{% trans "Publish" %}</a>
    +					<a href="./{{ page.id }}/{{ lang }}/unpublish/?redirect_language={{ preview_language }}&redirect_page_id={{ request.GET.page_id }}" class="js-ajax-submit">{% trans "Unpublish" %}</a>
    +					<a href="./{{ page.id }}/{{ lang }}/publish/?redirect_language={{ preview_language }}&redirect_page_id={{ request.GET.page_id }}" class="js-ajax-submit">{% trans "Publish" %}</a>
     				</div>
     				{% endif %}
     			{% else %}
    
  • cms/tests/admin.py+7 3 modified
    @@ -704,14 +704,14 @@ def test_change_publish_unpublish(self):
             with self.login_user_context(permless):
                 request = self.get_request()
                 response = self.admin_class.publish_page(request, page.pk, "en")
    -            self.assertEqual(response.status_code, 403)
    +            self.assertEqual(response.status_code, 405)
                 page = self.reload(page)
                 self.assertFalse(page.is_published('en'))
     
                 request = self.get_request(post_data={'no': 'data'})
                 response = self.admin_class.publish_page(request, page.pk, "en")
    -            # Forbidden
                 self.assertEqual(response.status_code, 403)
    +            page = self.reload(page)
                 self.assertFalse(page.is_published('en'))
     
             admin_user = self.get_admin()
    @@ -747,6 +747,10 @@ def test_change_innavigation(self):
             with self.login_user_context(permless):
                 request = self.get_request()
                 response = self.admin_class.change_innavigation(request, page.pk)
    +            self.assertEqual(response.status_code, 405)
    +        with self.login_user_context(permless):
    +            request = self.get_request(post_data={'no': 'data'})
    +            response = self.admin_class.change_innavigation(request, page.pk)
                 self.assertEqual(response.status_code, 403)
             with self.login_user_context(permless):
                 request = self.get_request(post_data={'no': 'data'})
    @@ -806,7 +810,7 @@ def test_revert_page_redirects(self):
             admin_user = self.get_admin()
             self.page.publish("en")  # Ensure public copy exists before reverting
             with self.login_user_context(admin_user):
    -            response = self.client.get(admin_reverse('cms_page_revert_page', args=(self.page.pk, 'en')))
    +            response = self.client.post(admin_reverse('cms_page_revert_page', args=(self.page.pk, 'en')))
                 self.assertEqual(response.status_code, 302)
                 url = response['Location']
                 self.assertTrue(url.endswith('?%s' % get_cms_setting('CMS_TOOLBAR_URL__EDIT_OFF')))
    
  • cms/tests/publisher.py+3 3 modified
    @@ -342,7 +342,7 @@ def test_publish_home(self):
             self.assertEqual(Page.objects.all().count(), 1)
             superuser = self.get_superuser()
             with self.login_user_context(superuser):
    -            response = self.client.get(admin_reverse("cms_page_publish_page", args=[page.pk, 'en']))
    +            response = self.client.post(admin_reverse("cms_page_publish_page", args=[page.pk, 'en']))
                 self.assertEqual(response.status_code, 302)
                 self.assertEqual(response['Location'], "http://testserver/en/?%s" % get_cms_setting('CMS_TOOLBAR_URL__EDIT_OFF'))
     
    @@ -381,7 +381,7 @@ def test_publish_admin(self):
             page = self.create_page("test_admin", published=False)
             superuser = self.get_superuser()
             with self.login_user_context(superuser):
    -            response = self.client.get(admin_reverse("cms_page_publish_page", args=[page.pk, 'en']))
    +            response = self.client.post(admin_reverse("cms_page_publish_page", args=[page.pk, 'en']))
                 self.assertEqual(response.status_code, 302)
             page = Page.objects.get(pk=page.pk)
     
    @@ -396,7 +396,7 @@ def test_publish_wrong_lang(self):
                 ):
                 with self.login_user_context(superuser):
                     with force_language('de'):
    -                    response = self.client.get(admin_reverse("cms_page_publish_page", args=[page.pk, 'en']))
    +                    response = self.client.post(admin_reverse("cms_page_publish_page", args=[page.pk, 'en']))
             self.assertEqual(response.status_code, 302)
             page = Page.objects.get(pk=page.pk)
     
    
  • cms/tests/reversion_tests.py+1 1 modified
    @@ -246,7 +246,7 @@ def test_publish_limits(self):
                     self.assertEqual(Revision.objects.all().count(), 5)
                     for x in range(10):
                         publish_url = URL_CMS_PAGE + "%s/en/publish/" % page_pk
    -                    response = self.client.get(publish_url)
    +                    response = self.client.post(publish_url)
                         self.assertEqual(response.status_code, 302)
                     self.assertEqual(Revision.objects.all().count(), 4)
     
    
f77cbc607d6e

Merge pull request #4218 from divio/issues/merge_csrf_fix

https://github.com/divio/django-cmsIacopo SpallettiJun 27, 2015via ghsa
7 files changed · +51 12
  • cms/admin/pageadmin.py+6 0 modified
    @@ -928,6 +928,7 @@ def change_template(self, request, object_id):
                 helpers.make_revision_with_plugins(page, request.user, message)
             return HttpResponse(force_unicode(_("The template was successfully changed")))
     
    +    @require_POST
         @wrap_transaction
         def move_page(self, request, page_id, extra_context=None):
             """
    @@ -1013,6 +1014,7 @@ def copy_language(self, request, page_id):
                     helpers.make_revision_with_plugins(page, request.user, message)
                 return HttpResponse("ok")
     
    +    @require_POST
         @wrap_transaction
         def copy_page(self, request, page_id, extra_context=None):
             """
    @@ -1046,6 +1048,7 @@ def copy_page(self, request, page_id, extra_context=None):
             context.update(extra_context or {})
             return HttpResponseRedirect('../../')
     
    +    @require_POST
         @wrap_transaction
         @create_revision()
         def publish_page(self, request, page_id, language):
    @@ -1146,6 +1149,7 @@ def cleanup_history(self, page, publish=False):
                             revision.delete()
                             deleted.append(revision.pk)
     
    +    @require_POST
         @wrap_transaction
         def unpublish(self, request, page_id, language):
             """
    @@ -1181,6 +1185,7 @@ def unpublish(self, request, page_id, language):
                 path = "%s?language=%s&page_id=%s" % (path, request.GET.get('redirect_language'), request.GET.get('redirect_page_id'))
             return HttpResponseRedirect(path)
     
    +    @require_POST
         @wrap_transaction
         def revert_page(self, request, page_id, language):
             page = get_object_or_404(Page, id=page_id)
    @@ -1316,6 +1321,7 @@ def preview_page(self, request, object_id, language):
                 page.site.domain, url)
             return HttpResponseRedirect(url)
     
    +    @require_POST
         def change_innavigation(self, request, page_id):
             """
             Switch the in_navigation of a page
    
  • cms/static/cms/js/modules/cms.changelist.js+11 2 modified
    @@ -180,8 +180,17 @@ $(document).ready(function () {
     				// cancel if not confirmed
     				if(!confirm(that.options.lang.publish.replace('§', $(this).text().toLowerCase()))) return false;
     
    -				// publish page and update
    -				window.location.href = $(this).attr('href');
    +				// send post request to prevent xss attacks
    +				$.ajax({
    +					'type': 'post',
    +					'url': $(this).prop('href'),
    +					'success': function () {
    +						CMS.API.Helpers.reloadBrowser();
    +					},
    +					'error': function (request) {
    +						throw new Error(request);
    +					}
    +				});
     			});
     		},
     
    
  • cms/static/cms/js/modules/cms.toolbar.js+21 1 modified
    @@ -213,7 +213,27 @@ $(document).ready(function () {
     
     				// in case of the publish button
     				btn.find('.cms_publish-page').bind(that.click, function (e) {
    -					if(!confirm(that.config.lang.publish)) e.preventDefault();
    +					if(!confirm(that.config.lang.publish)) {
    +						e.preventDefault();
    +					}
    +				});
    +
    +				btn.find('.cms_btn-publish').bind(that.click, function (e) {
    +					e.preventDefault();
    +					// send post request to prevent xss attacks
    +					$.ajax({
    +						'type': 'post',
    +						'url': $(this).prop('href'),
    +						'data': {
    +							'csrfmiddlewaretoken': CMS.config.csrf
    +						},
    +						'success': function () {
    +							CMS.API.Helpers.reloadBrowser();
    +						},
    +						'error': function (request) {
    +							throw new Error(request);
    +						}
    +					});
     				});
     			});
     		},
    
  • cms/templates/admin/cms/page/tree/menu_item.html+2 2 modified
    @@ -30,8 +30,8 @@
     				{% if lang in page.languages %}
     				<div class="language-tooltip" hidden="hidden">
     					{% trans "Pick an action:" %}
    -					<a href="./{{ page.id }}/{{ lang }}/unpublish/?redirect_language={{ preview_language }}&redirect_page_id={{ request.GET.page_id }}">{% trans "Unpublish" %}</a>
    -					<a href="./{{ page.id }}/{{ lang }}/publish/?redirect_language={{ preview_language }}&redirect_page_id={{ request.GET.page_id }}">{% trans "Publish" %}</a>
    +					<a href="./{{ page.id }}/{{ lang }}/unpublish/?redirect_language={{ preview_language }}&redirect_page_id={{ request.GET.page_id }}" class="js-ajax-submit">{% trans "Unpublish" %}</a>
    +					<a href="./{{ page.id }}/{{ lang }}/publish/?redirect_language={{ preview_language }}&redirect_page_id={{ request.GET.page_id }}" class="js-ajax-submit">{% trans "Publish" %}</a>
     				</div>
     				{% endif %}
     			{% else %}
    
  • cms/tests/admin.py+7 3 modified
    @@ -704,14 +704,14 @@ def test_change_publish_unpublish(self):
             with self.login_user_context(permless):
                 request = self.get_request()
                 response = self.admin_class.publish_page(request, page.pk, "en")
    -            self.assertEqual(response.status_code, 403)
    +            self.assertEqual(response.status_code, 405)
                 page = self.reload(page)
                 self.assertFalse(page.is_published('en'))
     
                 request = self.get_request(post_data={'no': 'data'})
                 response = self.admin_class.publish_page(request, page.pk, "en")
    -            # Forbidden
                 self.assertEqual(response.status_code, 403)
    +            page = self.reload(page)
                 self.assertFalse(page.is_published('en'))
     
             admin_user = self.get_admin()
    @@ -747,6 +747,10 @@ def test_change_innavigation(self):
             with self.login_user_context(permless):
                 request = self.get_request()
                 response = self.admin_class.change_innavigation(request, page.pk)
    +            self.assertEqual(response.status_code, 405)
    +        with self.login_user_context(permless):
    +            request = self.get_request(post_data={'no': 'data'})
    +            response = self.admin_class.change_innavigation(request, page.pk)
                 self.assertEqual(response.status_code, 403)
             with self.login_user_context(permless):
                 request = self.get_request(post_data={'no': 'data'})
    @@ -806,7 +810,7 @@ def test_revert_page_redirects(self):
             admin_user = self.get_admin()
             self.page.publish("en")  # Ensure public copy exists before reverting
             with self.login_user_context(admin_user):
    -            response = self.client.get(admin_reverse('cms_page_revert_page', args=(self.page.pk, 'en')))
    +            response = self.client.post(admin_reverse('cms_page_revert_page', args=(self.page.pk, 'en')))
                 self.assertEqual(response.status_code, 302)
                 url = response['Location']
                 self.assertTrue(url.endswith('?%s' % get_cms_setting('CMS_TOOLBAR_URL__EDIT_OFF')))
    
  • cms/tests/publisher.py+3 3 modified
    @@ -342,7 +342,7 @@ def test_publish_home(self):
             self.assertEqual(Page.objects.all().count(), 1)
             superuser = self.get_superuser()
             with self.login_user_context(superuser):
    -            response = self.client.get(admin_reverse("cms_page_publish_page", args=[page.pk, 'en']))
    +            response = self.client.post(admin_reverse("cms_page_publish_page", args=[page.pk, 'en']))
                 self.assertEqual(response.status_code, 302)
                 self.assertEqual(response['Location'], "http://testserver/en/?%s" % get_cms_setting('CMS_TOOLBAR_URL__EDIT_OFF'))
     
    @@ -381,7 +381,7 @@ def test_publish_admin(self):
             page = self.create_page("test_admin", published=False)
             superuser = self.get_superuser()
             with self.login_user_context(superuser):
    -            response = self.client.get(admin_reverse("cms_page_publish_page", args=[page.pk, 'en']))
    +            response = self.client.post(admin_reverse("cms_page_publish_page", args=[page.pk, 'en']))
                 self.assertEqual(response.status_code, 302)
             page = Page.objects.get(pk=page.pk)
     
    @@ -396,7 +396,7 @@ def test_publish_wrong_lang(self):
                 ):
                 with self.login_user_context(superuser):
                     with force_language('de'):
    -                    response = self.client.get(admin_reverse("cms_page_publish_page", args=[page.pk, 'en']))
    +                    response = self.client.post(admin_reverse("cms_page_publish_page", args=[page.pk, 'en']))
             self.assertEqual(response.status_code, 302)
             page = Page.objects.get(pk=page.pk)
     
    
  • cms/tests/reversion_tests.py+1 1 modified
    @@ -246,7 +246,7 @@ def test_publish_limits(self):
                     self.assertEqual(Revision.objects.all().count(), 5)
                     for x in range(10):
                         publish_url = URL_CMS_PAGE + "%s/en/publish/" % page_pk
    -                    response = self.client.get(publish_url)
    +                    response = self.client.post(publish_url)
                         self.assertEqual(response.status_code, 302)
                     self.assertEqual(Revision.objects.all().count(), 4)
     
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

8

News mentions

0

No linked articles in our index yet.