Someone found a way to crash your intern's Super Nintendo hobby — and filed a CVE for it
CVE-2026-39199 is an out-of-bounds heap write in the ReadUPSPatch function within memmap.cpp of snes9x, a freeware Super Nintendo Entertainment System emulator used for retro gaming. The bug exists in versions 1.52 through 1.63. When parsing a crafted .ups patch file, the code accumulates a relative offset via XPSdecode without verifying that the offset stays within the Memory.ROM buffer, allowing a heap write past the allocation boundary. The practical result is an application crash (denial of service). Modern OS mitigations (ASLR, DEP/NX) make code execution from this heap corruption impractical. The fix — commit 96b3661 — adds a single bounds check: relative < CMemory::MAX_ROM_SIZE.
The vendor score of LOW / 2.9 is accurate *for the software's own user base* — hobbyist gamers who download ROM patches from the internet. But for an enterprise security team managing 10,000 hosts, even LOW overstates the operational relevance. Snes9x is a consumer entertainment application with zero enterprise function. It does not run as a service, does not listen on a network port, does not handle business data, does not execute with elevated privileges, and should not appear on managed endpoints under any reasonable software-allowlisting policy. If your asset inventory shows snes9x installed, the conversation is about unauthorized software policy, not CVE remediation.
3 steps from start to impact.
Attacker crafts a malicious .ups patch file
.ups file with manipulated XPSdecode values that produce an arbitrarily large relative offset. This is straightforward — the UPS format is simple and documented, and a PoC crash archive already exists publicly. No special tooling is required beyond a hex editor or a short Python script.- Knowledge of UPS file format
- Ability to create files
- The attacker is building a weapon that can only crash a game emulator — there is no lateral movement, privilege escalation, or data exfiltration payload.
Victim obtains and loads the malicious .ups file
.ups file and place it alongside a SNES ROM so that snes9x loads it during ROM patching. This is a local attack vector — there is no remote trigger. The user must be actively using snes9x and deliberately loading patch files, which is a niche retro-gaming activity.- Snes9x 1.52–1.63 installed on the target host
- User actively loading .ups patch files from untrusted sources
- No application allowlisting blocking snes9x execution
- Enterprise endpoints should not have snes9x installed — application allowlisting or endpoint management policies block unapproved software
- The user population actively loading SNES ROM patches on corporate machines is effectively zero
- Even on personal machines, loading .ups files is a deliberate, manual action — not a drive-by
Heap write triggers application crash
.ups file, the unbounded relative offset causes a write past the Memory.ROM heap allocation. The operating system's memory protections (guard pages, ASLR, DEP) terminate the process. The emulator crashes. That is the entire impact — no persistence, no privilege change, no data touched.- Steps 1–2 completed successfully
- ASLR and DEP prevent the heap corruption from becoming code execution
- The crash affects only the snes9x process — no system-level impact, no service disruption, no data loss
- Network segmentation / firewall rules — irrelevant. The vulnerability is local file-based, not network-exploitable.
- WAF / IDS / IPS — irrelevant. No network traffic is involved in exploitation.
- Patching snes9x itself — while technically possible (build from the fixed commit), spending enterprise change-management cycles patching a game emulator is a misallocation of resources. Remove it instead.
The supporting signals.
| In-the-Wild Exploitation | None. Not listed in CISA KEV. No known campaigns. No threat actor interest — the target (a game emulator) has zero value to any threat model. |
|---|---|
| Proof of Concept | Public. Researcher Karan Saini published a detailed writeup including a crash PoC archive that reliably crashes snes9x 1.63 on Windows. No weaponized exploit beyond DoS. |
| EPSS | 0.00155 (~0.15 percentile) — bottom of the distribution. FIRST's model confirms near-zero exploitation probability. |
| CISA KEV | Not listed. No federal agency remediation deadline. |
| CVSS Vector | CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L — Local access, high complexity, no privilege required but no user interaction modeled (debatable — loading a .ups file *is* user interaction), scope unchanged, availability-only impact rated Low. |
| Affected Versions | snes9x 1.52 through 1.63 (all intermediate releases). The vulnerable function ReadUPSPatch was introduced with UPS support. |
| Fixed Version | No formal release yet — fix is in commit 96b3661 on the main branch. Debian/Ubuntu packages (libretro-snes9x, snes9x-gtk snap) may or may not have backported the fix. |
| Scanning / Exposure | Not applicable. Snes9x is a desktop GUI application. It does not listen on network ports. Shodan/Censys/GreyNoise have zero relevance. The only "exposure" metric is whether your endpoint management shows snes9x installed. |
| Disclosure Date | 2026-06-17, last modified 2026-10-21. |
| Reporting Researcher | Karan Saini (independent), who documented the discovery process using LLM-assisted code auditing. |
Sources.
Why this verdict
- Not enterprise software. Snes9x is a hobbyist Super Nintendo emulator. It has no enterprise function, no server deployment mode, no network-facing surface, and no role in any business process. It should not exist on managed endpoints.
- Local-only, user-initiated DoS. The attack requires the victim to manually load a crafted
.upsfile into the emulator. The impact is a process crash — no code execution, no data exposure, no privilege escalation, no persistence. - Zero high-value-role applicability. Snes9x does not occupy any enterprise role — it is not identity infrastructure, not a hypervisor, not CI/CD, not a network edge device, not a database engine, not a security agent, not OT/ICS. The deployment-role blast radius analysis produces an empty set.
- Role multiplier: (a) *Low-value role (hobbyist workstation):* the only plausible deployment. Chain succeeds → emulator crashes → user restarts it. Blast radius: single process on a single host. (b) *Typical enterprise role:* does not exist. (c) *High-value role:* does not exist. No floor applies because snes9x is categorically outside the enterprise software taxonomy. Zero percent of snes9x installs serve an enterprise infrastructure function.
- EPSS confirms irrelevance. At 0.00155, the exploitation probability model places this CVE in the noise floor — consistent with a low-impact bug in niche consumer software.
Why not higher?
There is no scenario in which this CVE warrants enterprise patching resources. The affected software is a game emulator with no business function. The impact ceiling is a process crash. Even if you accept the vendor's LOCAL/HIGH-COMPLEXITY/AVAILABILITY-ONLY scoring at face value, the 2.9 applies to end users who choose to run the software — not to enterprise defenders. Upgrading this to LOW would imply it deserves a place in your backlog, and it does not.
Why not lower?
IGNORE is the lowest severity in the noisgate scale. There is no lower rating to consider.
Crowdsourced verification payload.
Run on any managed Windows endpoint (or via your RMM/endpoint management tool) with standard user privileges. Invoke: powershell -ExecutionPolicy Bypass -File .\Check-CVE-2026-39199.ps1. This checks whether snes9x is installed and, if so, whether the installed version falls in the vulnerable range.
#Requires -Version 5.1
<#
Check-CVE-2026-39199.ps1
Detects whether snes9x 1.52-1.63 is present on this host.
Output: VULNERABLE / PATCHED / UNKNOWN
Exit codes: 1 = VULNERABLE, 0 = PATCHED, 2 = UNKNOWN
#>
$found = $false
$vulnerable = $false
# Check common install paths and running processes
$searchPaths = @(
"$env:ProgramFiles\Snes9x",
"${env:ProgramFiles(x86)}\Snes9x",
"$env:LOCALAPPDATA\Snes9x",
"$env:APPDATA\Snes9x",
"$env:USERPROFILE\Downloads\snes9x*",
"$env:USERPROFILE\Desktop\snes9x*"
)
# Also check if snes9x is running
$procs = Get-Process -Name 'snes9x*' -ErrorAction SilentlyContinue
if ($procs) {
Write-Host "[!] snes9x process is currently running: $($procs.Path -join ', ')"
$found = $true
$vulnerable = $true
}
# Search filesystem
foreach ($p in $searchPaths) {
$exes = Get-ChildItem -Path $p -Filter 'snes9x*.exe' -Recurse -ErrorAction SilentlyContinue
foreach ($exe in $exes) {
$found = $true
$ver = $exe.VersionInfo.ProductVersion
Write-Host "[*] Found snes9x at: $($exe.FullName) (version: $ver)"
# snes9x versions 1.52 through 1.63 are vulnerable
if ($ver -match '^1\.(5[2-9]|6[0-3])') {
$vulnerable = $true
Write-Host "[!] Version $ver is in the vulnerable range (1.52-1.63)"
} elseif ($ver) {
Write-Host "[+] Version $ver may be outside the vulnerable range"
} else {
Write-Host "[?] Could not determine version — assuming vulnerable if v1.63 era"
$vulnerable = $true
}
}
}
# Check snap/scoop/winget
try {
$wingetList = winget list --name snes9x 2>$null
if ($wingetList -match 'snes9x') {
Write-Host "[*] snes9x found via winget"
$found = $true
$vulnerable = $true
}
} catch { }
if (-not $found) {
Write-Host "PATCHED — snes9x not found on this host."
exit 0
} elseif ($vulnerable) {
Write-Host "VULNERABLE — snes9x 1.52-1.63 detected. Remove as unauthorized software."
exit 1
} else {
Write-Host "UNKNOWN — snes9x found but version could not be confirmed."
exit 2
}