VYPR
Moderate severityNVD Advisory· Published Jul 17, 2024· Updated Mar 13, 2025

CVE-2024-39126

CVE-2024-39126

Description

Roundup before 2.4.0 allows XSS via JavaScript in PDF, XML, and SVG documents.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Roundup before 2.4.0 allows stored XSS via embedded JavaScript in PDF, XML, and SVG file attachments.

Vulnerability

CVE-2024-39126 is a stored cross-site scripting (XSS) vulnerability in the Roundup issue tracker, affecting versions prior to 2.4.0. The bug allows PDF, XML, and SVG files attached to an issue to contain embedded JavaScript that executes when the file is accessed [1]. The root cause is that Roundup did not sanitize or restrict the execution of JavaScript within these file types, nor did it enforce a Content Security Policy (CSP) for downloaded files [4].

Exploitation

An attacker with the ability to attach files to an issue (typically any authenticated user) can upload a crafted PDF, XML, or SVG file containing embedded JavaScript. When other users view the attached file in their browser, the embedded script executes in the context of the Roundup application [1][4]. No additional authentication or network position is required beyond standard issue attachment privileges. The attack surface includes all interfaces where attachments are displayed — primarily the web UI, but also potentially email and REST endpoints if they serve file content directly in the browser.

Impact

Successful exploitation enables an attacker to perform arbitrary actions on behalf of the victim, such as stealing session cookies, modifying issue data, escalating privileges, or defacing pages. Since the injected script runs in the context of the Roundup tracker, it can access all functionality available to the authenticated user viewing the file. This could lead to account takeover, data exfiltration, or lateral movement within the tracker's environment [1][4].

Mitigation

The vulnerability is fixed in Roundup release 2.4.0. The fix applies two controls: PDF files are now downloaded with the Content-Disposition: attachment header so they are not displayed inline in the browser, and a Content Security Policy is enforced for all download files to prevent script execution in SVG files [1][4]. Users unable to upgrade immediately should configure their web server or reverse proxy to serve uploaded files with appropriate CSP headers and ensure PDF/XML/SVG attachments are not rendered inline [3].

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.

PackageAffected versionsPatched versions
roundupPyPI
< 2.4.02.4.0

Affected products

2

Patches

1
860e3c8d07b0

fix(security): fix CVE-2024-39124, CVE-2024-39124, and CVE-2024-39125

https://github.com/roundup-tracker/roundupJohn RouillardJul 9, 2024via ghsa
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('&lt;script&gt;')
    +        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&lt;/script&gt;&lt;script&gt;;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&lt;/script&gt;&lt;script&gt;;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

News mentions

0

No linked articles in our index yet.