This is less a front-door break-in than someone on the hallway Wi-Fi guessing the lock reset ritual
CVE-2026-28747 is a weak key generation flaw in Milesight AIOT camera firmware that can let an attacker bypass authorization and recover or abuse admin access material. Milesight and CISA tie it to a very broad model set, but the fixed builds show the affected population is fragmented across many firmware branches: examples include 51.7.0.77-r12 and earlier for MS-Cxx63-PD family, 63.8.0.5-r3 and earlier for MS-Cxx66/62/72-xxxG1, 45.8.0.2-AIoT-r4 and earlier for MS-Cxx66-xxxxGOPC, and 63.8.0.4-r1-NX and earlier for MS-Cxx66/72-{RFI,FI}PKG1.
The vendor's HIGH label is technically defensible but operationally inflated for most enterprises. The exploit chain needs adjacent-network positioning, high-complexity conditions, and user interaction according to the published CVSS; that means this is usually a *post-initial-access* or *same-segment attacker* problem on camera or OT networks, not a mass internet spray-and-pray event.
4 steps from start to impact.
Get onto the camera segment
nmap or ARP discovery rather than a CVE-specific exploit.- Adjacent-network access to the camera management path
- Routing or switching that permits reachability to camera web/API services
- Most mature deployments place cameras on isolated VLANs
- NAC, port security, or jump-host-only admin paths can block the prerequisite entirely
Capture or influence the weak key exchange
bettercap or Ettercap to watch or influence the exchange when an admin authenticates or performs the relevant action.- Visibility into local camera traffic or ability to induce a target admin action
- Victim interaction consistent with
UI:Rin the CVSS record
- Requires timing and proximity, not just raw IP reachability
- HTTPS interception, management jump hosts, or simply inactive admin sessions sharply reduce chances
Derive admin access material
- Captured protocol material from a vulnerable firmware branch
- Enough protocol understanding to reproduce the key derivation weakness
- No source-backed public PoC was found
- Custom firmware differences across many product branches increase attacker engineering cost
Log in and tamper with surveillance operations
- Recovered or bypassed admin authorization
- Reachability to the management interface
- Per-device impact is meaningful but not automatically enterprise-wide
- Central VMS controls, config drift monitoring, and separate credential stores can contain spread
The supporting signals.
| In-the-wild status | No authoritative exploitation evidence found in reviewed sources; not KEV-listed as of this assessment. |
|---|---|
| Proof-of-concept availability | No public PoC confirmed in reviewed sources. The attack appears to require custom analysis despite the public advisory. |
| EPSS | Provided intel says 0.00017; that is extremely low and consistent with a niche, hard-to-reach exploit path. |
| KEV status | Not listed in CISA KEV. That removes the strongest current signal for immediate emergency handling. |
| CVSS vector reality check | AV:A/AC:H/PR:N/UI:R means adjacent network, high complexity, no credentials, but *user interaction required*; that is a materially narrower real-world population than a typical unauthenticated remote internet bug. |
| Affected versions | Broad model coverage, but across many separate branches. Examples: MS-Cxx63-PD <= 51.7.0.77-r12, MS-Cxx66/62/72-xxxG1 <= 63.8.0.5-r3, MS-Cxx66-xxxxGOPC <= 45.8.0.2-AIoT-r4, MS-Cxx66/72-{RFI,FI}PKG1 <= 63.8.0.4-r1-NX. |
| Fixed versions | Examples from Milesight's notice: 51.7.0.77-r13, 63.8.0.5-r4, 45.8.0.2-AIoT-r5, 63.8.0.5-r2-NX, T_45.8.0.3-r10, T_61.8.0.4-r4, T_63.8.0.4-r4. |
| Scanning / exposure data | No CVE-specific internet telemetry from GreyNoise, Shodan, Censys, or FOFA was found in reviewed sources. Generic Censys research shows internet cameras are commonly exposed, but this CVE's AV:A requirement means raw exposure counts overstate reachable risk. |
| Disclosure and reporting | Disclosed 2026-04-27. Milesight credits SingCERT for reporting the vulnerability bundle. |
| Vendor impact statement | Milesight says the flaw can let an attacker decrypt the administrator password and compromise the account; that impact is real, but only after the attacker clears the adjacent-network and interaction hurdles. |
noisgate verdict.
The decisive factor is attacker position: this bug needs adjacent-network access, which usually implies the attacker is already on the camera or OT segment. Add the published AC:H and UI:R prerequisites plus the lack of KEV, PoC, or exploitation evidence, and this stops looking like a broad enterprise emergency and starts looking like a contained post-compromise amplifier.
Why this verdict
- Downgraded for attacker position:
AV:Ais not internet-remote; it usually means the attacker already reached the camera VLAN, OT segment, or local broadcast domain. - Downgraded for compounding friction: the vendor vector also includes
AC:HandUI:R, so the attacker needs both a finicky path and some victim-triggered condition rather than a one-packet unauthenticated hit. - Downgraded for weak threat-intel signals: no KEV entry, no source-backed in-the-wild campaigns, and no authoritative public PoC found. The provided EPSS is near-zero, which matches the narrow reachable population.
Why not higher?
If this were unauthenticated remote over the public internet, or if there were active campaigns against exposed Milesight fleets, this would be a different conversation. The impact can be ugly on a security camera, but the path to exploitation is too constrained to justify HIGH or CRITICAL for most enterprises.
Why not lower?
This is still an admin-compromise bug on surveillance infrastructure, not harmless paper-cut crypto hygiene. In flat or poorly segmented deployments, a foothold on the local network can translate into loss of camera integrity, surveillance blind spots, and misuse of device trust inside a physical-security environment.
What to do — in priority order.
- Isolate camera management paths — Keep cameras and NVRs on dedicated VLANs with no direct user-subnet access. This directly attacks the
AV:Aprerequisite; for a MEDIUM issue there is no fixed mitigation deadline, but apply it during normal operations and keep it in place until remediation is completed within 365 days. - Constrain admin access to jump hosts — Allow web/API administration only from hardened management stations or bastions, not general-purpose desktops. That reduces the user-interaction opportunity and makes local MITM on admin sessions much harder; maintain until patched within the 365-day remediation window.
- Monitor for local MITM behavior — Alert on ARP spoofing, duplicate gateway MACs, unexpected camera-management clients, and unusual admin logons to camera interfaces. This will not prevent exploitation alone, but it is the best detection layer for the prerequisite steps while you work through remediation.
- Rotate camera admin credentials after upgrading — Because Milesight states the weakness can expose administrator passwords, treat patched devices as potentially credential-exposed until passwords are changed. Do this as part of remediation, completed within the 365-day window, and prioritize any flat-network sites first.
- Internet-edge blocking alone doesn't solve this if the attacker is already on the same internal or OT segment; the published vector is adjacent, not necessarily internet remote.
- EDR on endpoints does almost nothing for the camera itself; the meaningful controls are segmentation, admin-path restriction, and network monitoring around the device.
- Password complexity by itself is not enough if the protocol weakness allows decryption or bypass during the vulnerable exchange.
Crowdsourced verification payload.
Run this on an auditor workstation, CMDB worker, or CI job that already knows the camera *model family* and current firmware version; it does not need target-host shell access. Invoke it as python3 verify_milesight_cve_2026_28747.py --model 'MS-Cxx63-PD' --version '51.7.0.77-r12' or python3 verify_milesight_cve_2026_28747.py --model 'MS-Cxx66-xxxxGOPC' --version '45.8.0.2-AIoT-r4'. No elevated privileges required.
#!/usr/bin/env python3
# Verify exposure to CVE-2026-28747 for Milesight camera firmware families.
# Usage:
# python3 verify_milesight_cve_2026_28747.py --model 'MS-Cxx63-PD' --version '51.7.0.77-r12'
# Exit codes:
# 0 = PATCHED
# 1 = VULNERABLE
# 2 = UNKNOWN / unsupported family / bad input
import argparse
import re
import sys
FAMILY_FIX = {
'MS-Cxx63-PD': '51.7.0.77-r13',
'MS-Cxx64-xPD': '51.7.0.77-r13',
'MS-Cxx73-xPD': '51.7.0.77-r13',
'MS-Cxx75-xxPD': '51.7.0.77-r13',
'MS-Cxx83-xPD': '51.7.0.77-r13',
'MS-Cxx74-PA': '3x.8.0.3-r13',
'MS-C8477-HPG1': '63.8.0.4-r4',
'MS-C8477-PC': '48.8.0.4-r4',
'MS-C5321-FPE': '62.8.0.4-r6',
'MS-Cxx72-xxxPE': '61.8.0.5-r2',
'MS-Cxx62-xxxPE': '61.8.0.5-r2',
'MS-Cxx52-xxxPE': '61.8.0.5-r2',
'MS-Cxx66-xxxPE': '61.8.0.5-r2',
'MS-Cxx66-xxxGPE': '61.8.0.5-r2',
'MS-Cxx61-xxxPE': '61.8.0.5-r2',
'MS-Cxx67-xxxPE': '61.8.0.5-r2',
'MS-Cxx71-xxxPE': '61.8.0.5-r2',
'MS-Cxx41-xxxPE': '61.8.0.5-r2',
'MS-Cxx76-PE': '61.8.0.5-r2',
'MS-Cxx65-PE': '61.8.0.5-r2',
'MS-Cxx66-xxxG1': '63.8.0.5-r4',
'MS-Cxx62-xxxG1': '63.8.0.5-r4',
'MS-Cxx72-xxxG1': '63.8.0.5-r4',
'MS-CQxx31-xxxG1': '63.8.0.5-r2',
'MS-CQxx68-xxxG1': '63.8.0.5-r2',
'MS-CQxx72-xxxG1': '63.8.0.5-r2',
'MS-Nxxxx-NxE': '7x.9.0.19-r6',
'MS-Nxxxx-xxC': '7x.9.0.19-r6',
'MS-Nxxxx-xxE': '7x.9.0.19-r6',
'MS-Nxxxx-xxG': '7x.9.0.19-r6',
'MS-Nxxxx-xxH': '7x.9.0.19-r6',
'MS-Nxxxx-xxT': '7x.9.0.19-r6',
'PMC8266-FPE': '61.8.0.4-r1',
'PMC8266-FGPE': '61.8.0.4-r1',
'PM3322-E': '61.8.0.3-r5',
'TS4466-X4RIPG1': '63.8.0.4-r4',
'TS5366-X12RIPG1': '63.8.0.4-r4',
'TS8266-X4RIPG1': '63.8.0.4-r4',
'TS4466-X4RIVPG1': '63.8.0.4-r4',
'TS4466-RFIVPG1': '63.8.0.4-r4',
'TS8266-X4RIVPG1': '63.8.0.4-r4',
'TS8266-RFIVPG1': '63.8.0.4-r4',
'TS4466-X4RIWG1': '63.8.0.4-r4',
'TS8266-X4RIWG1': '63.8.0.4-r4',
'TS5510-GVH': '47.8.0.4-r8',
'TS5510-GH': '47.8.0.4-r8',
'TS5511-GVH': '47.8.0.4-r8',
'TS2966-X12TPE': '61.8.0.4-r4',
'TS4466-X4RPE': '61.8.0.4-r4',
'TS5366-X12PE': '61.8.0.4-r4',
'TS8266-X4PE': '61.8.0.4-r4',
'TS2966-X12TVPE': '61.8.0.4-r4',
'TS4466-X4RVPE': '61.8.0.4-r4',
'TS5366-X12VPE': '61.8.0.4-r4',
'TS8266-X4VPE': '61.8.0.4-r4',
'TS4441-X36RPE': '61.8.0.4-r4',
'TS4441-X36RE': '61.8.0.4-r4',
'TS4466-X4RWE': '61.8.0.4-r4',
'TS8266-X4WE': '61.8.0.4-r4',
'MS-C2964-RFLPC': '45.8.0.3-r10',
'MS-C2972-RFLPC': '45.8.0.3-r10',
'MS-C2966-RFLWPC': '45.8.0.3-r10',
'TS2866-X4TPC': '45.8.0.3-r10',
'TS2866-X4TVPC': '45.8.0.3-r10',
'TS2866-X4TGPC': '45.8.0.3-r10',
'TS2841-X36TPC': '45.8.0.3-r10',
'TS2841-X36TPC/W': '45.8.0.3-r10',
'TS2867-X5TPC': '45.8.0.3-r10',
'TS2961-X12TPC': '45.8.0.3-r10',
'TS8266-FPC/P': '45.8.0.3-r10',
'MS-C2966-X12RLPC': '45.8.0.3-r10',
'MS-C2966-X12RLVPC': '45.8.0.3-r10',
'MS-C5366-X12LPC': '45.8.0.3-r10',
'MS-C5366-X12LVPC': '45.8.0.3-r10',
'MS-C5361-X12LPC': '45.8.0.3-r10',
'MS-Cxx66-xxxxGOPC': '45.8.0.2-AIoT-r5',
'SC211': '21.1.0.8-r5',
'SP111': '52.8.0.4-r6',
'MS-Cxx66-RFIPKG1': '63.8.0.5-r2-NX',
'MS-Cxx72-RFIPKG1': '63.8.0.5-r2-NX',
'MS-Cxx66-FIPKG1': '63.8.0.5-r2-NX',
'MS-Cxx72-FIPKG1': '63.8.0.5-r2-NX',
}
def normalize_model(value: str) -> str:
return value.strip()
def tokenize_version(value: str):
# Extract numeric components in order; this handles prefixes like T_, CQ_, NX, AIoT, etc.
nums = re.findall(r'\d+', value)
return [int(x) for x in nums]
def compare_versions(a: str, b: str):
# Returns -1 if a < b, 0 if a == b, 1 if a > b, 99 if comparison is too ambiguous.
# Wildcard family fix strings like 3x.8.0.3-r13 or 7x.9.0.19-r6 are handled by replacing x with 0,
# which is conservative for determining PATCHED vs VULNERABLE on that family baseline.
a_norm = a.replace('x', '0').replace('X', '0')
b_norm = b.replace('x', '0').replace('X', '0')
ta = tokenize_version(a_norm)
tb = tokenize_version(b_norm)
if not ta or not tb:
return 99
max_len = max(len(ta), len(tb))
ta += [0] * (max_len - len(ta))
tb += [0] * (max_len - len(tb))
if ta < tb:
return -1
if ta > tb:
return 1
return 0
def main():
parser = argparse.ArgumentParser(description='Check Milesight firmware family against CVE-2026-28747 fixed versions')
parser.add_argument('--model', required=True, help='Milesight model family or exact model as used in the advisory')
parser.add_argument('--version', required=True, help='Current firmware version string reported by the device or inventory')
args = parser.parse_args()
model = normalize_model(args.model)
version = args.version.strip()
if model not in FAMILY_FIX:
print('UNKNOWN')
print(f'Unsupported or unrecognized model family: {model}', file=sys.stderr)
sys.exit(2)
fixed = FAMILY_FIX[model]
cmp_result = compare_versions(version, fixed)
if cmp_result == 99:
print('UNKNOWN')
print(f'Could not compare version {version} to fixed baseline {fixed}', file=sys.stderr)
sys.exit(2)
if cmp_result >= 0:
print('PATCHED')
print(f'{model} current={version} fixed_baseline={fixed}')
sys.exit(0)
else:
print('VULNERABLE')
print(f'{model} current={version} fixed_baseline={fixed}')
sys.exit(1)
if __name__ == '__main__':
main()
If you remember one thing.
Sources
- Milesight Security Notice - Vulnerabilities in Milesight Cameras
- CISA ICS Advisory ICSA-26-113-03
- CISA CSAF JSON for ICSA-26-113-03
- CVE record via OpenCVE
- CIRCL vulnerability record with NVD-enriched metadata
- Milesight release note 45.8.0.2-AIoT-r5
- CISA Known Exploited Vulnerabilities Catalog
- Censys blog on internet cameras exposure
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.