Skip to content

HTML special characters are not escaped in some PEP headers #5096

Closed

Description

@gmilde

The Docutils project recieved a security bug report regarding the Docutils PEP parser.
While the affected code is not used by "python/peps/" anymore, the problem persists in the function that replaced it in peps/sphinx-extensions.

Please advise me how to report the problem securely.

Activity

  1. hugovk commented on Aug 15, 2026

    @hugovk
    Member

    Please see the security policy to report issues about this repo:

    https://github.com/python/peps/security/policy

  2. JelleZijlstra commented on Aug 15, 2026

    @JelleZijlstra
    Member

    If the security issue is just that a PEP author could inject code into a header that runs JS in a viewer's browser, I'm not sure that's a big issue: the only people with commit access to the PEPs also have the commit access to the PEP rendering pipeline, so they could already inject arbitrary JS.

  3. gmilde commented on Aug 31, 2026

    @gmilde
    Author

    The exploit requires "strange" text in the PEP source, so this is no open gap, indeed.
    The report to Docutils is now public: https://sourceforge.net/p/docutils/bugs/519/

    The use of a "raw" HTML node for email masking is present in peps/pep_sphinx_extensions/pep_processor/transforms/pep_zero.py.
    Cf. commit https://sourceforge.net/p/docutils/code/10394/ to see how Docutils fixed this.

  4. hugovk commented on Sep 1, 2026

    @hugovk
    Member

    Thanks for the followup. The fix is pretty small, but I think we're fine as we won't merge strange text like the below, so let's close.

    Title: </title><script>alert('XSS')</script>
    Author: `"><img src=x onerror=alert(1)> <evil@example.com>`_
  5. JelleZijlstra commented on Sep 1, 2026

    @JelleZijlstra
    Member

    Come to think of it though, is this a problem for the RTD previews we automatically generate?

  6. hugovk commented on Sep 1, 2026

    @hugovk
    Member

    Hmm, I guess so! Okay, let's re-open and fix :)

  7. reopened this on Sep 1, 2026
  8. hugovk commented on Sep 1, 2026

    @hugovk
    Member

    Well, the build falls over for either of:

    Title: </title><script>alert('XSS')</script>
    Author: `"><img src=x onerror=alert(1)> <evil@example.com>`_

    Like:

    sphinx.errors.SphinxParallelError: docutils.utils.SystemMessage: /Users/hugo/github/peps/peps/pep-0000.rst:759: (ERROR/3) invalid PEP number script>alert('XSS')</script> <9999
    
    sphinx.errors.SphinxParallelError: docutils.utils.SystemMessage: /Users/hugo/github/peps/peps/numerical.rst:3704: (WARNING/2) Inline interpreted text or phrase reference start-string without end-string.
    

    But these do trigger:

    Sponsor: `"><img src=x onerror=alert(1)> <mailto:evil@example.com>`__
    BDFL-Delegate: `"><svg onload=alert(2)> <mailto:evil2@example.com>`__
    

    However, someone could always just do this:

    .. raw:: html
    
       <script>alert('XSS via raw directive')</script>
       <img src=x onerror=alert('also this')>

    Or indeed put any JS in the build and include the normal way, so it doesn't really matter much if we fix this.

    Anyway, I've opened #5113 in case we do want to cover header bits.

  9. JelleZijlstra commented on Sep 1, 2026

    @JelleZijlstra
    Member

    Yeah, a malicious PR could also just edit the processor and create a preview with injections.

    Your PR seems like a positive though, so let's land it.

  10. Rosuav commented on Sep 1, 2026

    @Rosuav
    Contributor

    However, someone could always just do this:

    .. raw:: html

    <script>alert('XSS via raw directive')</script>

    <img src=x onerror=alert('also this')>
    Or indeed put any JS in the build and include the normal way, so it doesn't really matter much if we fix this.

    Then maybe the approach we should take is to have previews only automatically activated for known users, and for everyone else, the PR waits without a preview until someone has approved it for rendering. I believe that can be done?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions