CVE-2024-39125
Description
Roundup before 2.4.0 allows XSS via a SCRIPT element in an HTTP Referer header.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Roundup before 2.4.0 allows stored XSS by executing a script tag placed in the HTTP Referer header.
CVE-2024-39125 is a cross-site scripting (XSS) vulnerability in the Roundup issue tracker affecting versions prior to 2.4.0. The bug arises from improper sanitization of the HTTP Referer header. When a user-supplied Referer header contains a SCRIPT element, Roundup fails to escape the input, allowing the malicious script to be reflected and executed in the error reporting page that displays the invalid Referer [1][3].
No authentication is required to trigger the vulnerability; an attacker merely needs to craft a URL that causes a victim's browser to send an HTTP request with a malicious Referer header pointing to a compromised or attacker-controlled page. The script executes in the context of the Roundup instance, requiring the victim to be logged into the tracker for full impact. The attack surface is the web-based error reporting feature that logs and displays Referer header values [1].
Successful exploitation enables an attacker to execute arbitrary JavaScript in the victim's browser within the Roundup application's origin. This can lead to session hijacking, defacement, theft of sensitive data, or unauthorized actions performed on behalf of the authenticated user [1][3].
The issue is fixed in Roundup 2.4.0. The vendor has published a commit addressing the vulnerability [1] and provides directions for fixing older trackers that cannot be immediately upgraded [3]. Users are strongly advised to update to 2.4.0 or apply the recommended patch.
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
roundupPyPI | < 2.4.0 | 2.4.0 |
Affected products
2- Roundup/Roundupdescription
Patches
1860e3c8d07b0fix(security): fix CVE-2024-39124, CVE-2024-39124, and CVE-2024-39125
33 files changed · +538 −70
CHANGES.txt+15 −0 modified@@ -16,6 +16,21 @@ python 3.6 or newer (3.4/3.5 might work, but they are not tested). Fixed: +- CVE-2024-39124 - The classhelpers (_generic.help.html) are + vulnerable to an XSS attack. A specially crafted URL that used + that endpoint would result in running a script embedded in the + URL. (Found/reported by Alec Romano (4rdr), fix/tests John + Rouillard) +- CVE-2024-39125 - If the Referer header is set to a script tag, + it will be executed when the error in the Referer header is + reported. (Found/reported by Alec Romano (4rdr), fix/tests John + Rouillard) +- CVE-2024-39126 - PDF, XML and SVG files attached to an issue can contain + embedded JavaScript. This JavaScript was executed when the file was + accessed. PDF files are now downloaded and not displayed in the + browser. A content security policy is added for all download files + which prevents code execution in SVG files. (Found/reported by Alec + Romano (4rdr), fix/tests John Rouillard) - issue2551282 - MySQL utf8mb4 issues and issue2551115 - Use utf8mb4 as a default for MySQL instead of utf8 The default database type and collations have been set to:
doc/acknowledgements.txt+2 −0 modified@@ -40,6 +40,8 @@ Norbert Schlemmer - docker support Bharath Kanama, Nikunj Thakkar, Patel Malav - classhelper web component development. +Alec Romano (4rdr) - identified multiple security issues + 2.3 ---
doc/announcement.txt+9 −5 modified@@ -4,7 +4,7 @@ release, so make sure to read `docs/upgrading.txt <https://www.roundup-tracker.org/docs/upgrading.html>`_ to bring your tracker up to date. -The 67 changes, as usual, include some new features and many +The 79 changes, as usual, include some new features and many bug fixes. Note that you should run ``roundup-admin ... migrate`` to @@ -22,12 +22,16 @@ You can install it with:: then unpack and test/install from the tarball. -Beta 2 includes a small change to the classic tracker's -classhelper.js to fix a bug found after beta 1 was released. - Among the notable improvements in 2.4.0 from the 2.3.0 release are: +* three CVE's have been fixed. One requires changes to your + tracker's home directory. The other two are fixed by + installing 2.4.0. See + https://www.roundup-tracker.org/docs/security.html for + details and instructions on how to fix these in 2.4.0 and + earlier releases. + * new classhelper component thanks to a team of students from CS682 at U-Mass Boston. This fixes many issues with the old classhelper. It is implemented as a web-component @@ -87,7 +91,7 @@ release are: * sqlite version 1 and StructuredText support removed. The file CHANGES.txt has a detailed list of feature -additions and bug fixes (67) for each release. The most +additions and bug fixes for each release. The most recent changes from there are at the end of this announcement. Also see the information in doc/upgrading.txt.
doc/CVE.txt+100 −0 added@@ -0,0 +1,100 @@ +.. comments: + This file is a temporary way to post CVE notifications before + a release. + + Document the CVE fix info in upgrading.txt. Publishing + upgrading.txt would push info on the next release not the current + release. + + So we comment out a reference anchor in upgrading.txt and use that + comment to extract the section from upgrading.txt into CVE.txt. + The extracted section gets the same anchor that is in upgrading.txt, + but is is not commented out. + + Then we add a summary to the list of CVE's in security.txt using a + :ref: to the anchor. If CVE.txt is part of the build and + upgrading.txt has a commented out anchor, security.txt entries link + to CVE.html in the generated documentation. + + In upgrading.txt add a + + .. comment: _CVE-2024-39124: + + before the section for the CVE (use the real CVE number). At the + end of the CVE section add an end comment: + + .. comment: end of CVE include marker + + Update security.txt with a :ref: to the CVE section. E.G. a + security.txt references look like: + + * `CVE-2024-39124`_ - :ref:`classhelpers (_generic.help.html) are + vulnerable to an XSS attack. <CVE-2024-39124>` Requires fixing + tracker homes. + + where <CVE-2024-39124> is the reference. The same reference anchor + is present (commented out) in upgrading.txt. In CVE.txt you + replicate the existing anchor and include to extract the content + section from upgrading.txt. E.G. + + .. _CVE-2024-39124: + + .. include:: upgrading.txt + :start-after: .. comment: _CVE-2024-39124: + :end-before: .. comment: end of CVE + + After building the docs, install docs/security.html and + docs/CVE.html on the web site. Use the security.html URL + on the web site to update the CVE report. + + When the release is ready, replace 'comment: _CVE' with '_CVE' in + upgrading.txt. This makes the anchors in upgrading.txt live. + + Then disable CVE.txt by removing CVE.txt from contents.txt in the + toctree hidden section. Also add CVE.txt to exclude_patterns in + conf.py. + + No change needs to happen to security.txt as it's using a :ref: and + we just changed the location for the ref so sphinx will get the + links correct. + + Now build the docs and publish to the web site. + +=========== +Roundup CVE +=========== + +This is a list of remediation for CVE's that are not fixed in the +latest release. When the latest release fixes the CVE, see `the +upgrading doc <upgrading.html>`_ for these details. + +.. contents:: + :local: + :depth: 2 + +.. _CVE-2024-39124: + +.. note:: + + Prior to the release of Roundup 2.4.0, you can access updated + tracker templates that address CVE-2024-39124 from + `CVE-2024-39124-templates.zip + <../CVE-2024-39124-templates.zip>`_. Download and extract the zip + file to generate a templates subdirectory containing the classic, + minimal and other tracker templates. + +.. include:: upgrading.txt + :start-after: .. comment: _CVE-2024-39124: + :end-before: .. comment: + +.. _CVE-2024-39125: + +.. include:: upgrading.txt + :start-after: .. comment: _CVE-2024-39125: + :end-before: .. comment: + +.. _CVE-2024-39126: + +.. include:: upgrading.txt + :start-after: .. comment: _CVE-2024-39126: + :end-before: .. comment: end of CVE include marker
doc/security.txt+40 −8 modified@@ -1,20 +1,51 @@ .. meta:: :description: Documentation on how to report security issues with - Roundup. Also index to security related portions in other - Roundup documentation. How to verify distribution using gpg. + Roundup. Index to recent security related (CVE) descriptions + in other Roundup documentation. How to verify distribution + using gpg. .. index:: single: Reporting Security Issues + single: CVE announcements single: Security Issues, Reporting + single: Security Issues, Remediation + single: Security Issues, CVE announcements ======================= Roundup Security Issues ======================= -This page documents how to report security issues and verify the -signatures for Roundup releases. +This page documents CVE's fixed starting with version 2.4.0, how to +report security issues, and verify the signatures for Roundup +source release tarballs. + +.. contents:: + :local: + :depth: 2 + +CVE Announcements +----------------- + + * `CVE-2024-39124`_ - :ref:`classhelpers (_generic.help.html) are + vulnerable to an XSS attack. <CVE-2024-39124>` Requires fixing + tracker homes. + * `CVE-2024-39125`_ - :ref:`if Referer header is set to a script tag, + it will be executed. <CVE-2024-39125>` Fixed in release 2.4.0, + directions available for fixing in prior versions. + * `CVE-2024-39126`_ - :ref:`PDF, XML and SVG files downloaded from an + issue can contain embedded JavaScript which is + executed. <CVE-2024-39126>` Fixed in release 2.4.0, directions + available for fixing in prior versions. + +.. _CVE-2024-39124: + https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-39124 +.. _CVE-2024-39125: + https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-39125 +.. _CVE-2024-39126: + https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-39126 + Reporting Security Issues ------------------------- @@ -88,8 +119,8 @@ Once you have loaded the public key, you need a detached signature for your release. -Download and Verify with Detached Signature -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Download Detached Signature and Verify +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This needs to be done once for each release you wish to verify. @@ -137,5 +168,6 @@ If something is wrong you will see:: gpg: using RSA key 411E354B5D1AF26125D621221F2DD0CB756A76D8 gpg: BAD signature from "Roundup Team (signing key for roundup releases) <roundup-devel at lists.sourceforge.net>" -**do not use** the tarball if the signature is BAD. Email the -roundup-devel mailing list if you have this happen to you. +**do not use** the tarball if the signature is BAD. Email the mailing +list: roundup-devel at lists.sourceforge.net if you have this happen +to you.
doc/upgrading.txt+283 −5 modified@@ -122,12 +122,290 @@ This will insert the bad API login rate limiting settings. Also if you have ``html_version`` set to ``xhtml``, you will get an error. -Use of xhtml html_version disabled (required) ---------------------------------------------- +.. comment: _CVE-2024-39124: -If you enabled xhtml formatted templates, you will need to -change them to html (html4) format. Also change the value of -``html_version`` from ``xhtml`` to ``html``. +Fix for CVE-2024-39124 in help/calendar popups (recommended) +------------------------------------------------------------ + +Classhelper components accessed via URL using ``@template=help``, +``@template=calendar`` or other template frame in the classhelper +can run JavaScript embedded in the URL. If user clicks on a +malicious URL that: + + * arrives in an email, + * is embedded in a note left on a ticket [#markdown-note]_, + * left on some other web page + +the JavaScript code will be executed. This vulnerability seems to +be limited to manually crafted URL's. It has not been generated +by using Roundup's mechanism for generating classhelper URLs. + +The files that need to be changed to fix this depend on the +template used to create the tracker. Check the +TEMPLATE-INFO.txt file in your tracker home. The template +name is the first component of the ``Name`` field. For +example trackers with Names like:: + + Name: classic-bugtracker + + Name: devel-mytracker + +were derived from the ``classic`` and ``devel`` templates +respectively. If your tracker is derived from the jinja2 +template, you may not be affected as it doesn't provide +classhelpers by default. If you aren't sure which tracker +template was used to create your tracker home, check the +``html/help.html`` file for the word ``Javascript``. If your +help.html is missing the word ``Javascript``, follow the +directions for the classic template. + +If you have not modified the original tracker html +templates, you can copy replacement files from the new +templates supplied with release 2.4.0. If you install 2.4.0 +in a `new virtual environment +<installation.html#standard-installation>`_, you can use the +command ``roundup-admin templates`` to find the installation +path of the default templates. + +If your template was based on the classic template, replace the +following files in your tracker: + + * html/_generic.calendar.html + * html/_generic.help-list.html + * html/_generic.help-submit.html + * html/_generic.help.html + * html/user.help-search.html + * html/user.help.html + +If your template was based on the minimal template, replace the +following files in your tracker: + + * html/_generic.calendar.html + * html/_generic.help.html + +If your template was based on the responsive or devel templates, +replace the following files in your tracker: + + * html/_generic.calendar.html + * html/_generic.help-submit.html + * html/help.html + * html/user.help-search.html + * html/user.help.html + +As an example, assume Roundup's virtual environment is +``/tools/roundup``. The classic tracker's default template will +be in ``/tools/roundup/share/roundup/templates/classic``. +Copy +``/tools/roundup/share/roundup/templates/classic/html/_generic.calendar.html`` +to ``html/_generic.calendar.html`` in your tracker's home +directory. Repeat for every one of the files that needs to +be replaced. + +If you have made local changes to your popup/classhelper +files or have created new help templates based on the +existing ones, don't copy the default files. Instead, follow +the directions below to modify each file as needed for your +template. + +In the examples below, your script tag may differ. For +example it could include:: + + tal:attributes="nonce request/client/client_nonce" + +If it does, keep the differences. You want to make changes +to remove the structure option but keep the rest of the +valid attributes. + +Most files have a small script that sets a few variables +from the settings in the URL. You should change:: + + <script language="Javascript" type="text/javascript" + tal:content="structure string: + // this is the name of the field in the original form that we're working on + form = window.opener.document.${request/form/form/value}; + field = '${request/form/property/value}';"> + +to:: + + <script language="Javascript" type="text/javascript" + tal:content="string: + // this is the name of the field in the original form that we're working on + form = window.opener.document.${request/form/form/value}; + field = '${request/form/property/value}';"> + +by removing the ``structure`` keyword from the tal:content +block. This will html escape the settings in the URL. This +neutralizes an attempt to execute JavaScript by manipulating +the URL. Most of the files use code similar to this. + +A few files have more extensive JavaScript embedded in the same +script tag. To handle this you should split it into two scripts +and encode the replaced strings. For example, change:: + + <script language="Javascript" type="text/javascript" + tal:content="structure string:<!-- + // this is the name of the field in the original form that we're working on + form = parent.opener.document.${request/form/form/value}; + callingform=form + field = '${request/form/property/value}'; + var listform = null + function listPresent() { + return document.frm_help.cb_listpresent.checked + [more code skipped] + +to:: + + <script language="Javascript" type="text/javascript" + tal:content="string: + // this is the name of the field in the original form that we're working on + form = parent.opener.document.${request/form/form/value}; + callingform=form + field = '${request/form/property/value}';"> + </script> + <script language="Javascript" type="text/javascript" + tal:content="string: + var listform = null + function listPresent() { + return document.frm_help.cb_listpresent.checked + [...] + +modifying the original by: + + 1. removing the ``structure`` keyword and the HTML comment + marker ``<!--``. This encodes the replaced strings. + 2. adding ``">`` at the end of the line that sets ``field`` closes + the script tag. + 3. adding:: + + </script> + <script language="Javascript" type="text/javascript" + tal:content="string: + + after the line used in step 2, to ends the first script and + starts a new script. + +Just removing the ``structure`` directive is enough to fix the +bug. Splitting the large script into two parts: + + 1. one that has replaced strings with values taken from the URL + 2. one that has no replaced strings + +allows use of ``structure`` on the script with no replaced +strings should it be required for your tracker. + +.. [#markdown-note] If you are using markdown formatting for your tracker's notes, + the user will see the markdown label rather than the long + (suspicious) URL. You may want to add something like:: + + a[href*=\@template]::after { + content: ' [' attr(href) ']'; + } + + to your css. This displays the URL inside square brackets if + the href has ``@template`` in it. It is placed after the link + label. + +Fix CVE in earlier versions of Roundup (recommended) +---------------------------------------------------- + +If you are upgrading to version 2.4.0, you can skip this +section. These fixes are already present in 2.4.0. + +This section is for people who can not upgrade yet, and want +to fix the issues. + +.. comment: _CVE-2024-39125: + +Referer value not escaped CVE-2024-39125 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Malicious JavaScript inserted into a page can change the value of +the Referer header to include a script. If a link on that page +points to a Roundup tracker, that script will be executed. The +technique to change the header will result in a change of the URL +in the browser's address bar, but this is easily missed. + +Fix this by editing ``cgi/client.py``, and change:: + + except (UsageError, Unauthorised) as msg: + csrf_ok = False + self.form_wins = True + self._error_message = msg.args + +to:: + + except (UsageError, Unauthorised) as msg: + csrf_ok = False + self.form_wins = True + self.add_error_message(' '.join(msg.args)) + +This escapes the Referer value an prevents it from being +executed. + +.. comment: _CVE-2024-39126: + +Stop JavaScript execution from attached files CVE-2024-39126 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If an SVG, XML or PDF file that includes malicious JavaScript is +attached to an issue, downloading the file will cause the +JavaScript to run. + +In ``cgi/client.py`` add the Content-Security-Policy line +after the existing ``nosniff`` line so it looks like:: + + # exception handlers. + self.determine_language() + self.db.i18n = self.translator + self.setHeader("X-Content-Type-Options", "nosniff") + self.setHeader("Content-Security-Policy", "script-src 'none'") + self.serve_file(designator) + +(the example is reindented for display). + +This should prevent SVG and XML files with embedded scripts +from running. + +If your version of Roundup is old enough that the ``nosniff`` +line is missing, search for ``serve_file(designator)`` and add +both setHeader lines. + +.. warning:: + + If your users use older browsers that don't support Content + Security Policies (e.g. Internet Explorer), you must + remove ``text/xml`` and ``image/svg`` from + ``mime_type_allowlist`` as explained below for + ``application/pdf``. + +PDF files can also embed JavaScript. Many browsers include +PDF viewers that may not support disabling scripting. The +safest way to handle this is to force a download of the PDF +file and use a PDF viewer with scripting disabled. To force +downloading, look in ``cgi/client.py`` for +``mime_type_allowlist`` and remove the line for +``application/pdf``. + +Version 2.4.0 allows you to `modify the mime_type_allowlist +using interfaces.py +<admin_guide.html#controlling-browser-handling-of-attached-files>`_. +This will allow you to enable in-browser reading of PDF +files when you upgrade to 2.4.0 if you wish. + +Note that a `Content Security Policy as documented in the admin +guide +<admin_guide.html#adding-a-web-content-security-policy-csp>`_ is +not applied it to a direct download. This requires adding an +explicit CSP header as above. + +.. comment: end of CVE include marker + +XHTML no longer supported (required) +------------------------------------ + +If your ``config.ini`` sets ``html_version`` to ``xhtml``, +you need to change it to ``html``. Then you need to change +your tracker's templates to html from xhtml. Note that the default Roundup templates use html4 so it is unlikely that your templates are xhtml based. See
roundup/cgi/client.py+7 −1 modified@@ -835,7 +835,7 @@ def inner_main(self): except (UsageError, Unauthorised) as msg: csrf_ok = False self.form_wins = True - self._error_message = msg.args + self.add_error_message(' '.join(msg.args)) # If csrf checks pass. Run actions etc. # handle_action() may handle a form submit action. @@ -873,7 +873,13 @@ def inner_main(self): # exception handlers. self.determine_language() self.db.i18n = self.translator + # prevent application/octet-stream mime type in header + # from being changed to some other type by the browser + # when mime sniffing. self.setHeader("X-Content-Type-Options", "nosniff") + # prevent script execution in downloaded SVG, XML files + # (or HTML files if enabled). + self.setHeader("Content-Security-Policy", "script-src 'none'") self.serve_file(designator) except SendStaticFile as file: self.serve_static_file(str(file))
share/roundup/templates/classic/html/_generic.calendar.html+1 −1 modified@@ -7,7 +7,7 @@ <title tal:content="string:Roundup Calendar"></title> <script language="Javascript" type="text/javascript" - tal:content="structure string: + tal:content="string: // this is the name of the field in the original form that we're working on form = window.opener.document.${request/form/form/value}; field = '${request/form/property/value}';" >
share/roundup/templates/classic/html/_generic.help.html+1 −1 modified@@ -9,7 +9,7 @@ tal:content="property | default" i18n:translate="" /> help - <span i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title> <script language="Javascript" type="text/javascript" - tal:content="structure string: + tal:content="string: // this is the name of the field in the original form that we're working on form = window.opener.document.${request/form/form/value}; field = '${request/form/property/value}';">
share/roundup/templates/classic/html/_generic.help-list.html+2 −3 modified@@ -4,11 +4,10 @@ <title>Search result for user helper</title> <link rel="stylesheet" type="text/css" href="@@file/style.css" /> <script language="Javascript" type="text/javascript" - tal:content="structure string:<!-- + tal:content="string: // this is the name of the field in the original form that we're working on form = parent.opener.document.${request/form/form/value}; - field = '${request/form/property/value}'; - //-->"></script> + field = '${request/form/property/value}';"></script> <script src="@@file/help_controls.js" type="text/javascript"></script> <script type="text/javascript"><!-- var text_field = parent.submit.document.frm_help.text_preview;
share/roundup/templates/classic/html/_generic.help-submit.html+6 −4 modified@@ -6,11 +6,14 @@ <tal:block tal:condition="python:'property' in request.form"> <title>Generic submit page for framed helper windows</title> <script language="Javascript" type="text/javascript" - tal:content="structure string:<!-- + tal:content="string: // this is the name of the field in the original form that we're working on form = parent.opener.document.${request/form/form/value}; callingform=form -field = '${request/form/property/value}'; +field = '${request/form/property/value}';"> +</script> + <script language="Javascript" type="text/javascript" + tal:content="structure string: var listform = null function listPresent() { return document.frm_help.cb_listpresent.checked @@ -35,8 +38,7 @@ var bol= listform != null alert('checkListForm: bol='+bol) return bol -} -//-->"> +}"> </script> <script src="@@file/help_controls.js" type="text/javascript"></script> </tal:block>
share/roundup/templates/classic/html/user.help.html+2 −3 modified@@ -14,11 +14,10 @@ tal:replace="config/TRACKER_NAME" /></tal:x></title> <script language="Javascript" type="text/javascript" tal:condition=false - tal:content="structure string:<!-- + tal:content="string: // this is the name of the field in the original form that we're working on form = window.opener.document.${form}; - field = '${field}'; - //-->"> + field = '${field}';"> </script> <script src="@@file/help_controls.js" tal:condition=false type="text/javascript"><!--
share/roundup/templates/classic/html/user.help-search.html+2 −3 modified@@ -5,11 +5,10 @@ <head> <title>Search input for user helper</title> <script language="Javascript" type="text/javascript" - tal:content="structure string:<!-- + tal:content="string: // this is the name of the field in the original form that we're working on form = parent.opener.document.${form}; - field = '${field}'; - //-->"> + field = '${field}';"> </script> <script type="text/javascript" src="@@file/help_controls.js"></script> <link rel="stylesheet" type="text/css" href="@@file/style.css" />
share/roundup/templates/devel/html/_generic.calendar.html+1 −1 modified@@ -7,7 +7,7 @@ <title tal:content="string:Roundup Calendar"></title> <script language="Javascript" type="text/javascript" - tal:content="structure string: + tal:content="string: // this is the name of the field in the original form that we're working on form = window.opener.document.${request/form/form/value}; field = '${request/form/property/value}';" >
share/roundup/templates/devel/html/_generic.help-submit.html+5 −2 modified@@ -6,11 +6,14 @@ <tal:block tal:condition="python:'property' in request.form"> <title>Generic submit page for framed helper windows</title> <script language="Javascript" type="text/javascript" - tal:content="structure string:<!-- + tal:content="string: // this is the name of the field in the original form that we're working on form = parent.opener.document.${request/form/form/value}; callingform=form -field = '${request/form/property/value}'; +field = '${request/form/property/value}';"> + </script> + <script language="Javascript" type="text/javascript" + tal:content="string: var listform = null function listPresent() { return document.frm_help.cb_listpresent.checked
share/roundup/templates/devel/html/help.html+2 −3 modified@@ -10,11 +10,10 @@ <tal:x i18n:name="what" tal:content="what" i18n:translate="" /> help - <span i18n:name="tracker" tal:replace="config/TRACKER_NAME" /> </title> - <script language="Javascript" type="text/javascript" tal:content="structure string:<!-- + <script language="Javascript" type="text/javascript" tal:content="string: // this is the name of the field in the original form that we're working on form = window.opener.document.${form}; - field = '${field}'; - //-->"> + field = '${field}';"> </script> <link rel="stylesheet" type="text/css" href="@@file/help.css" /> <script src="@@file/help_controls.js" type="text/javascript"></script>
share/roundup/templates/devel/html/user.help.html+1 −1 modified@@ -6,7 +6,7 @@ field request/form/property/value"> <tal:block metal:fill-slot="more-javascript"> <script language="javascript" type="text/javascript" - tal:content="structure string:form = parent.opener.document.${form}; + tal:content="string:form = parent.opener.document.${form}; callingform=form; field = '${field}';"></script> <script language="Javascript" type="text/javascript">
share/roundup/templates/devel/html/user.help-search.html+2 −3 modified@@ -5,11 +5,10 @@ <head> <title>Search input for user helper</title> <script language="Javascript" type="text/javascript" - tal:content="structure string:<!-- + tal:content="string: // this is the name of the field in the original form that we're working on form = parent.opener.document.${form}; - field = '${field}'; - //-->"> + field = '${field}';"> </script> <script type="text/javascript" src="@@file/help_controls.js"></script> <link rel="stylesheet" type="text/css" href="@@file/style.css" />
share/roundup/templates/minimal/html/_generic.calendar.html+1 −1 modified@@ -7,7 +7,7 @@ <title tal:content="string:Roundup Calendar"></title> <script language="Javascript" type="text/javascript" - tal:content="structure string: + tal:content="string: // this is the name of the field in the original form that we're working on form = window.opener.document.${request/form/form/value}; field = '${request/form/property/value}';" >
share/roundup/templates/minimal/html/_generic.help.html+1 −1 modified@@ -9,7 +9,7 @@ tal:content="property | default" i18n:translate="" /> help - <span i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title> <script language="Javascript" type="text/javascript" - tal:content="structure string: + tal:content="string: // this is the name of the field in the original form that we're working on form = window.opener.document.${request/form/form/value}; field = '${request/form/property/value}';">
share/roundup/templates/responsive/html/_generic.calendar.html+1 −1 modified@@ -7,7 +7,7 @@ <title tal:content="string:Roundup Calendar"></title> <script language="Javascript" type="text/javascript" - tal:content="structure string: + tal:content="string: // this is the name of the field in the original form that we're working on form = window.opener.document.${request/form/form/value}; field = '${request/form/property/value}';" >
share/roundup/templates/responsive/html/_generic.help-submit.html+5 −2 modified@@ -6,11 +6,14 @@ <tal:block tal:condition="python:'property' in request.form"> <title>Generic submit page for framed helper windows</title> <script language="Javascript" type="text/javascript" - tal:content="structure string:<!-- + tal:content="string: // this is the name of the field in the original form that we're working on form = parent.opener.document.${request/form/form/value}; callingform=form -field = '${request/form/property/value}'; +field = '${request/form/property/value}';"> + </script> + <script language="Javascript" type="text/javascript" + tal:content="structure string: var listform = null function listPresent() { return document.frm_help.cb_listpresent.checked
share/roundup/templates/responsive/html/help.html+2 −3 modified@@ -18,11 +18,10 @@ body { padding-top: 80px; padding-bottom: 40px; } </style> <link rel="stylesheet" href="@@file/bootstrap-responsive.min.css"> - <script language="Javascript" type="text/javascript" tal:content="structure string:<!-- + <script language="Javascript" type="text/javascript" tal:content="string: // this is the name of the field in the original form that we're working on form = window.opener.document.${form}; - field = '${field}'; - //-->"> + field = '${field}';"> </script> <link rel="stylesheet" type="text/css" href="@@file/help.css" /> <script src="@@file/help_controls.js" type="text/javascript"></script>
share/roundup/templates/responsive/html/user.help.html+1 −1 modified@@ -6,7 +6,7 @@ field request/form/property/value"> <tal:block metal:fill-slot="more-javascript"> <script language="javascript" type="text/javascript" - tal:content="structure string:form = parent.opener.document.${form}; + tal:content="string:form = parent.opener.document.${form}; callingform=form; field = '${field}';"></script> <script language="Javascript" type="text/javascript">
share/roundup/templates/responsive/html/user.help-search.html+2 −3 modified@@ -5,11 +5,10 @@ <head> <title>Search input for user helper</title> <script language="Javascript" type="text/javascript" - tal:content="structure string:<!-- + tal:content="string: // this is the name of the field in the original form that we're working on form = parent.opener.document.${form}; - field = '${field}'; - //-->"> + field = '${field}';"> </script> <script type="text/javascript" src="@@file/help_controls.js"></script> <link rel="stylesheet" type="text/css" href="@@file/style.css" />
test/test_cgi.py+12 −1 modified@@ -978,7 +978,7 @@ def wh(s): self.assertFalse('HTTP_PROXY' in cl.env) self.assertFalse('HTTP_PROXY' in os.environ) - def testCsrfProtection(self): + def testCsrfProtectionHtml(self): # need to set SENDMAILDEBUG to prevent # downstream issue when email is sent on successful # issue creation. Also delete the file afterwards @@ -1058,6 +1058,17 @@ def hasPermission(s, p, classname=None, d=None, e=None, **kw): del(cl.env['HTTP_REFERER']) del(out[0]) + # verify that HTTP_REFERER does not result in an XSS reflection + cl.env['HTTP_REFERER'] = '<script>alert(1)</script>' + cl.main() + match_at=out[0].find('<script>') + match_encoded_at=out[0].find('<script>') + print("\n\nresult of subtest 2a:", out[0]) + self.assertEqual(match_at, -1) # must not find unencoded script tag + self.assertEqual(match_encoded_at, 53) # must find encoded script tag + del(cl.env['HTTP_REFERER']) + del(out[0]) + cl.env['HTTP_ORIGIN'] = 'http://whoami.com' cl.main() match_at=out[0].find('Redirecting to <a href="http://whoami.com/path/issue1?@ok_message')
test/test_liveserver.py+19 −0 modified@@ -263,6 +263,24 @@ def test_start_in_german(self): self.assertTrue(b'Aufgabenliste' in f.content) self.assertTrue(b'dauerhaft anmelden?' in f.content) + def test_classhelper_reflection(self): + """ simple test that verifies that the generic classhelper + is escaping the url params correctly. + """ + f = requests.get(self.url_base() + "/keyword?@startwith=0&@template=help&properties=name&property=keyword&form=itemSynopsis</script><script>%3balert(1)%2f%2f&type=checkbox&@sort=name&@pagesize=50") + self.assertEqual(f.status_code, 200) + self.assertNotIn(b"<script>;alert(1)//;\n", f.content) + self.assertIn( + b"itemSynopsis</script><script>;alert(1)//;\n", + f.content) + + f = requests.get(self.url_base() + "/keyword?@startwith=0&@template=help&properties=name&property=keyword</script><script>%3balert(1)%2f%2f&form=itemSynopsis&type=checkbox&@sort=name&@pagesize=50") + self.assertEqual(f.status_code, 200) + self.assertNotIn(b"<script>;alert(1)//;\n", f.content) + self.assertIn( + b"keyword</script><script>;alert(1)//';</script>\n", + f.content) + def test_byte_Ranges(self): """ Roundup only handles one simple two number range, or a single number to start from: @@ -1308,6 +1326,7 @@ def test_new_issue_with_file_upload(self): f = session.get(self.url_base()+'/file%(file)s/text1.txt'%m.groupdict()) self.assertEqual(f.text, file_content) self.assertEqual(f.headers["X-Content-Type-Options"], "nosniff") + self.assertEqual(f.headers["Content-Security-Policy"], "script-src 'none'") print(f.text) def test_new_file_via_rest(self):
website/issues/html/_generic.calendar.html+1 −1 modified@@ -8,7 +8,7 @@ <script language="Javascript" type="text/javascript" tal:attributes="nonce request/client/client_nonce" - tal:content="structure string: + tal:content="string: // this is the name of the field in the original form that we're working on form = window.opener.document.${request/form/form/value}; field = '${request/form/property/value}';" >
website/issues/html/_generic.help.html+1 −1 modified@@ -11,7 +11,7 @@ tal:replace="config/TRACKER_NAME" /></title> <script language="Javascript" type="text/javascript" tal:attributes="nonce request/client/client_nonce" - tal:content="structure string: + tal:content="string: // this is the name of the field in the original form that we're working on form = window.opener.document.${request/form/form/value}; field = '${request/form/property/value}';">
website/issues/html/_generic.help-list.html+2 −3 modified@@ -5,11 +5,10 @@ <link rel="stylesheet" type="text/css" href="@@file/style.css" /> <script language="Javascript" type="text/javascript" tal:attributes="nonce request/client/client_nonce" - tal:content="structure string:<!-- + tal:content="string: // this is the name of the field in the original form that we're working on form = parent.opener.document.${request/form/form/value}; - field = '${request/form/property/value}'; - //-->"></script> + field = '${request/form/property/value}';"></script> <script src="@@file/help_controls.js" tal:attributes="nonce request/client/client_nonce" type="text/javascript"></script>
website/issues/html/_generic.help-submit.html+5 −2 modified@@ -7,11 +7,14 @@ <title>Generic submit page for framed helper windows</title> <script language="Javascript" type="text/javascript" tal:attributes="nonce request/client/client_nonce" - tal:content="structure string:<!-- + tal:content="string: // this is the name of the field in the original form that we're working on form = parent.opener.document.${request/form/form/value}; callingform=form -field = '${request/form/property/value}'; +field = '${request/form/property/value}';"></script> + <script language="Javascript" type="text/javascript" + tal:attributes="nonce request/client/client_nonce" + tal:content="string: var listform = null function listPresent() { return document.frm_help.cb_listpresent.checked
website/issues/html/user.help.html+2 −3 modified@@ -15,11 +15,10 @@ <script language="Javascript" type="text/javascript" tal:attributes="nonce request/client/client_nonce" tal:condition=false - tal:content="structure string:<!-- + tal:content="string: // this is the name of the field in the original form that we're working on form = window.opener.document.${form}; - field = '${field}'; - //-->"> + field = '${field}';"> </script> <script src="@@file/help_controls.js" tal:attributes="nonce request/client/client_nonce"
website/issues/html/user.help-search.html+2 −3 modified@@ -6,11 +6,10 @@ <title>Search input for user helper</title> <script language="Javascript" type="text/javascript" tal:attributes="nonce request/client/client_nonce" - tal:content="structure string:<!-- + tal:content="string: // this is the name of the field in the original form that we're working on form = parent.opener.document.${form}; - field = '${field}'; - //-->"> + field = '${field}';"> </script> <script type="text/javascript" src="@@file/help_controls.js" tal:attributes="nonce request/client/client_nonce"></script>
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-xjgw-ghrx-wfffghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-39125ghsaADVISORY
- github.com/pypa/advisory-database/tree/main/vulns/roundup/PYSEC-2024-64.yamlghsaWEB
- github.com/roundup-tracker/roundup/commit/860e3c8d07b05b77c6cdf5d0b6e7dbfe51b11631ghsaWEB
- www.roundup-tracker.orgghsaWEB
- www.roundup-tracker.org/docs/security.htmlghsaWEB
News mentions
0No linked articles in our index yet.