← Back to Feed CACHED · 2026-10-21 19:26:10 · CACHE_KEY CVE-2026-39199
CVE-2026-39199 · CWE-787 · Disclosed 2026-06-17

Snes9x UPS patch file out-of-bounds heap write via unbounded relative offset in ReadUPSPatch

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

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.

"A crash bug in a retro gaming emulator is not your problem to patch."
02 · The Attack Path

3 steps from start to impact.

STEP 01

Attacker crafts a malicious .ups patch file

The attacker constructs a .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.
Conditions required:
  • Knowledge of UPS file format
  • Ability to create files
Where this breaks in practice:
  • The attacker is building a weapon that can only crash a game emulator — there is no lateral movement, privilege escalation, or data exfiltration payload.
STEP 02

Victim obtains and loads the malicious .ups file

The victim must download the crafted .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.
Conditions required:
  • 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
Where this breaks in practice:
  • 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
Detection/coverage: Application inventory / software asset management tools will flag snes9x as unapproved software.
STEP 03

Heap write triggers application crash

When snes9x processes the malicious .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.
Conditions required:
  • Steps 1–2 completed successfully
Where this breaks in practice:
  • 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
03 · Compensating Control

1
IGNORE 0.0→IGNORE 0.0
Block snes9x via application allowlisting — If snes9x appears in your software inventory, the correct response is to block it as unauthorized software via your endpoint management platform (Intune, SCCM, Jamf, CrowdStrike Falcon Device Control, Carbon Black App Control). This is standard software governance, not CVE remediation. No noisgate mitigation SLA applies — this is an IGNORE verdict.
2
IGNORE 0.0→IGNORE 0.0
Remove snes9x from endpoints during routine software audits — As part of normal hygiene, flag and remove unapproved consumer applications. This eliminates the attack surface entirely. No SLA pressure — handle during your next scheduled software compliance sweep.
What doesn't work
  • 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.
04 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNone. 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 ConceptPublic. 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.
EPSS0.00155 (~0.15 percentile) — bottom of the distribution. FIRST's model confirms near-zero exploitation probability.
CISA KEVNot listed. No federal agency remediation deadline.
CVSS VectorCVSS: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 Versionssnes9x 1.52 through 1.63 (all intermediate releases). The vulnerable function ReadUPSPatch was introduced with UPS support.
Fixed VersionNo 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 / ExposureNot 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 Date2026-06-17, last modified 2026-10-21.
Reporting ResearcherKaran Saini (independent), who documented the discovery process using LLM-assisted code auditing.

Sources.

  1. OSV – CVE-2026-39199
  2. Karan Saini – snes9x OOB Write Analysis
  3. GitHub – Fix Commit 96b3661
  4. GitHub – snes9x Issue #1035
  5. OpenCVE – CVE-2026-39199
  6. Strix AI – CVE-2026-39199 Detail
  7. CyberStrike – CVE-2026-39199
05 · The Call

Final Verdict
↓ DOWNGRADED to IGNORE (0.0/10)

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 .ups file 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.

06 · Verification

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.

noisgate-verify.ps1
POWERSHELLREAD-ONLYSAFE
#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
}