CVE-2026-39199 Overview
CVE-2026-39199 is an out-of-bounds write vulnerability in snes9x 1.63, a popular Super Nintendo Entertainment System (SNES) emulator. The flaw resides in the UPS patch file parser inside memmap.cpp. A crafted .ups file can drive the patching routine to write beyond the bounds of the Memory.ROM buffer, leading to memory corruption and denial of service. The issue is classified under [CWE-787: Out-of-bounds Write]. Exploitation requires the victim to load a malicious patch file locally, and impact is limited to availability with no confidentiality or integrity loss reported.
Critical Impact
A crafted .ups file processed by snes9x 1.63 triggers an out-of-bounds write in the ROM patching loop, corrupting adjacent memory and crashing the emulator.
Affected Products
- snes9x 1.63 (SNES emulator)
- Builds incorporating the unpatched UPS patching logic in memmap.cpp
- Distributions packaging snes9x prior to commit 96b3661
Discovery Timeline
- 2026-06-17 - CVE-2026-39199 published to the National Vulnerability Database (NVD)
- 2026-06-17 - Last updated in NVD database
- Technical analysis published by Karan Saini at snes9x OOB Write Analysis
- Upstream fix tracked in snes9x GitHub issue #1035
Technical Details for CVE-2026-39199
Vulnerability Analysis
The vulnerability lives in the UPS patch handler in memmap.cpp. UPS is a binary delta format used to apply ROM modifications. The patcher reads a relative offset from the patch stream using XPSdecode, then walks forward writing XOR-modified bytes into Memory.ROM[relative++]. The unpatched loop never validates that relative stays within CMemory::MAX_ROM_SIZE. An attacker controls both the decoded offset and the byte sequence written. By supplying a large decoded relative value, the loop advances the index past the end of the allocated ROM buffer. Subsequent XOR writes land in adjacent heap memory, producing memory corruption and a process crash.
Root Cause
The root cause is missing bounds validation on the destination index during patch application. The outer loop checked the source buffer position but not the destination write position inside Memory.ROM. This omission allowed a single crafted UPS chunk to write past the ROM allocation boundary.
Attack Vector
Exploitation is local. An attacker must convince a snes9x user to open a malicious .ups file or place one alongside a ROM that the emulator auto-patches at load time. No authentication or network access is required, but user interaction is needed to load the file.
// Patch from snes9x commit 96b3661 - memmap.cpp UPS handler
uint32 relative = 0;
while(addr < size - 12) {
relative += XPSdecode(data, addr, size);
- while(addr < size - 12) {
+ while(addr < size - 12 && relative < CMemory::MAX_ROM_SIZE) {
uint8 x = data[addr++];
Memory.ROM[relative++] ^= x;
if(!x) break;
Source: snes9x commit 96b366100172723f6314c40e237b370f4f7b59f4. The fix adds a relative < CMemory::MAX_ROM_SIZE guard to the inner loop, blocking writes past the ROM buffer.
Detection Methods for CVE-2026-39199
Indicators of Compromise
- Unexpected snes9x process crashes immediately after loading a ROM with a co-located .ups patch file
- .ups files received from untrusted sources (forums, archives, email attachments) placed next to legitimate ROMs
- Crash dumps showing faulting writes inside the UPS patching routine in memmap.cpp
Detection Strategies
- Inventory installed snes9x binaries and flag versions at or below 1.63 that lack commit 96b3661
- Hash-match .ups files against known-bad samples referenced in the GitHub issue #1035
- Static-parse .ups files and reject patches whose cumulative decoded relative offsets exceed the target ROM size
Monitoring Recommendations
- Alert on snes9x process termination with access-violation or SIGSEGV exit codes on user workstations
- Monitor file-write activity that drops .ups files into emulator working directories from browsers or archive utilities
- Log endpoint crash telemetry for the snes9x binary and correlate with recent .ups file access
How to Mitigate CVE-2026-39199
Immediate Actions Required
- Update snes9x to a build that includes commit 96b3661 or later from the snes9x repository
- Remove untrusted .ups files from emulator ROM directories until the patched build is deployed
- Restrict execution of snes9x to standard user accounts so a crash cannot impact privileged sessions
Patch Information
The upstream fix is commit 96b366100172723f6314c40e237b370f4f7b59f4 in memmap.cpp. It adds a relative < CMemory::MAX_ROM_SIZE bounds check to the inner UPS patching loop, preventing writes past the end of Memory.ROM. Rebuild snes9x from source after pulling the commit, or install a distribution package that incorporates it.
Workarounds
- Do not load .ups patch files from untrusted sources until the patched build is installed
- Disable automatic patch application in snes9x and apply UPS patches with a separate validated tool that enforces ROM-size bounds
- Run snes9x inside a sandbox or container that limits the blast radius of a memory corruption crash
# Build snes9x from source with the fix applied
git clone https://github.com/snes9xgit/snes9x.git
cd snes9x
git checkout 96b366100172723f6314c40e237b370f4f7b59f4
cd unix && ./configure && make
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

