From 318e86339f81121c5ce4cbf83f43bd74d58af8b0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 21:56:25 +0000 Subject: [PATCH 1/2] Initial plan From ef54ae04ce5f31cc43f989308fa55934f57bffee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 22:00:24 +0000 Subject: [PATCH 2/2] Fix reflected XSS in composer mygraph view (issue #2794) Co-authored-by: deniszh <1227222+deniszh@users.noreply.github.com> --- webapp/graphite/composer/views.py | 7 ++++--- webapp/tests/test_xss.py | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/webapp/graphite/composer/views.py b/webapp/graphite/composer/views.py index f60c37bf6..09f4f50c6 100644 --- a/webapp/graphite/composer/views.py +++ b/webapp/graphite/composer/views.py @@ -21,6 +21,7 @@ from django.http import HttpResponse from django.conf import settings from django.core.exceptions import ObjectDoesNotExist +from django.utils.html import escape def composer(request): @@ -65,7 +66,7 @@ def mygraph(request): newGraph.save() except Exception: log.exception("Failed to create new MyGraph in /composer/mygraph/, graphName=%s" % graphName) - return HttpResponse("Failed to save graph %s" % graphName) + return HttpResponse("Failed to save graph %s" % escape(graphName)) return HttpResponse("SAVED") @@ -75,9 +76,9 @@ def mygraph(request): existingGraph.delete() except ObjectDoesNotExist: - return HttpResponse("No such graph '%s'" % graphName) + return HttpResponse("No such graph '%s'" % escape(graphName)) return HttpResponse("DELETED") else: - return HttpResponse("Invalid operation '%s'" % action) + return HttpResponse("Invalid operation '%s'" % escape(action)) diff --git a/webapp/tests/test_xss.py b/webapp/tests/test_xss.py index da9d17eed..4b6cf8d54 100644 --- a/webapp/tests/test_xss.py +++ b/webapp/tests/test_xss.py @@ -6,6 +6,8 @@ except ImportError: # Django < 1.10 from django.urls import reverse +from django.contrib.auth.models import User + from .base import TestCase # Silence logging during tests @@ -49,3 +51,25 @@ def test_find_xss_script_tag(self): for param in ('from', 'until'): response = self.client.get(url, {'query': 'test', param: xssStr}) self.assertXSS(response, status_code=400, msg_prefix='XSS detected in %s: ' % param) + + +class ComposerMyGraphXSSTest(TestCase): + def setUp(self): + self.user = User.objects.create_user('testxss', 'testxss@example.com', 'pass') + self.client.login(username='testxss', password='pass') + + def test_mygraph_xss_action(self): + """Test that XSS in the action parameter is properly escaped (issue #2794)""" + url = reverse('composer_mygraph') + xssStr = '">' + + response = self.client.get(url, {'action': xssStr, 'graphName': 'test'}) + self.assertXSS(response, msg_prefix='XSS detected in action: ') + + def test_mygraph_xss_graphname(self): + """Test that XSS in the graphName parameter is properly escaped (issue #2794)""" + url = reverse('composer_mygraph') + xssStr = '">' + + response = self.client.get(url, {'action': 'delete', 'graphName': xssStr}) + self.assertXSS(response, msg_prefix='XSS detected in graphName: ')