Security Research
The USB Camera That Freezes Windows: A usbvideo.sys Descriptor Parser DoS Microsoft Won't Fix
A usbvideo.sys descriptor-parser DoS: a USB Video device with bLength=0 can pin kernel CPU and block USB enumeration. MSRC closed it without a fix.

Executive Summary
Delphos Labs' automated binary and software artifact analysis platform surfaced a denial-of-service bug in Microsoft's USB Video Class driver,
usbvideo.sys. A malicious USB device provides a configuration descriptor that makes the Windows video driver loop forever during device enumeration. A Windows servicing change replaced a check that guaranteed forward progress with one that only validates buffer bounds, so a descriptor with bLength=0 now passes validation.The result is not just a failed camera. On the tested system, plugging in the device made one CPU core spin at 100% in kernel mode indefinitely and blocked USB enumeration system-wide. Unplugging the device failed to stop the spin because the thread was stuck in driver code, not waiting on hardware. Recovery required a forced reboot or power cycle.
We reported the issue to MSRC. On July 23, 2026, MSRC responded they did not consider it a bug and closed the case without a fix. No CVE was assigned.
Delphos identified the risky parser behavior directly from the compiled driver without source code or a sandbox. It also automatically produced a working proof of concept to test with the USB-device.
No Camera Required: The usbvideo.sys Enumeration Vulnerability
usbvideo.sys is the inbox Windows driver for USB Video Class devices. Every webcam that does not ship its own kernel driver binds to it. The driver is present on supported Windows installations whether or not a camera has ever been attached, and the vulnerable path runs during device enumeration, before any user-mode application opens the device.The installed population is every Windows build carrying the newer validation path. The reachable population is the subset of those machines with a physically accessible USB port.
It is also the exact threat model for kiosks, shared lab workstations, conference room machines, medical carts, and any unattended endpoint. The vulnerability is confirmed on one machine: usbvideo.sys 10.0.26100.7705 (x64) but it also affects the x86 and ARM architectures.
No user-mode application has to open the device. Plugging it in is the whole attack.
How do you find a parser bug in a compiled kernel driver?
Delphos’s platform analyzed
usbvideo.sys and flagged a descriptor-walking loop where parser progress depended on a length byte read from an untrusted USB descriptor. The platform also identified a feature-flagged validation path where a zero-length descriptor could be accepted as valid.It then reconstructed the relevant control flow around
DumpAndValidateGenericDescriptor, DumpAndValidateAllDescriptors, and DumpAndValidateAllDescriptorsEx. If bLength was zero, validation would return success and the caller would advance the parse pointer by zero bytes.The Delphos platform generated a PoC, a Teensy 3.2 firmware image that enumerates as a single-function USB Video Class device and serves the exact descriptor sequence needed to reach usbvideo.sys. We flashed it and confirmed the hang by hand.
What happens when a USB descriptor has bLength=0?
USB descriptors are length-prefixed. Every descriptor begins with bLength, and descriptor parsers must reject entries that cannot advance the cursor.
In the vulnerable
usbvideo.sys path, a descriptor with bLength=0 is accepted by the generic descriptor validator. The caller then does the normal descriptor-walk update:current = current + current->bLengthWith
bLength=0, current never changes. The loop parses the same descriptor forever.The tested driver was:
Driver: C:\Windows\System32\drivers\usbvideo.sys
Version: 10.0.26100.7705
SHA256: AD366CD2992C5EFE2B8ACB08FADFC17B4B6C2D2F58D98C6540FF5C0AA6ED75A1
Tested OS: Windows 11 25H2 / build 26200.7840
Impact: system-wide USB denial of serviceWhy did a Windows servicing fix make the driver less safe?
The relevant validator has two code paths controlled by the Windows feature flag
Feature_Servicing_UvcDescriptPointerFix (0x034f6e08). The newer path was enabled by default on the tested system.The flag is named for the fix it was intended to deliver. The path it enables accepts a descriptor the old code rejected.
The old path rejected a zero-length descriptor because it checked whether advancing would move the pointer forward:
if (&desc[desc->bLength] <= desc)
return ERROR;With
bLength=0, &desc[0] == desc, the old check fails safely.The new path checked only whether the descriptor length fit within the remaining buffer:
if (desc > end || end - desc < desc->bLength)
return ERROR;
return SUCCESS;
For
bLength=0, the remaining-buffer check passes. The validator returns success, and the caller advances by zero.The older check enforced both bounds and progress; the newer one enforces only bounds.
The vulnerable loop in
DumpAndValidateAllDescriptorsEx has the usual form:loop:
cmp current, end
jae done
lea rax, [current + 2]
cmp rax, end
ja done
call DumpAndValidateGenericDescriptor
test eax, eax
jnz error
movzx eax, byte ptr [current] ; bLength
add current, rax ; current += 0
jmp loop
A servicing change to correct pointer handling removed the property that made the original check safe.
Why doesn’t a composite device work?
A composite device with an Interface Association Descriptor routes through
usbccgp.sys first. usbccgp.sys rebuilds per-function descriptors and filters descriptors with bLength < 2, which strips the poison before usbvideo.sys sees it. The PoC avoids that by loading usbvideo.sys directly as the function driver. The two-byte minimum is already enforced one layer up, by a driver in the same stack.The rule
usbvideo.sys dropped is one the USB stack already applies elsewhere.The PoC firmware serves a 34-byte configuration descriptor:
Offset | Size | Descriptor | Purpose |
0 | 9 | Configuration | wTotalLength=34, one interface |
9 | 9 | Interface | VideoControl interface, no endpoints |
18 | 12 | Class-specific VC header | Valid UVC header, bInCollection=0 |
30 | 2 | Poison descriptor | bLength=0, bDescriptorType=0xFF |
32 | 2 | Padding | Keeps the caller's current+2 <= end check true |
The device must enumerate as a single-function UVC device:
bDeviceClass = 0x0E (Video)
bDeviceSubClass = 0x01 (VideoControl)
bDeviceProtocol = 0x00What does a USB device need to do to reach the vulnerable path?
The firmware is deliberately minimal. It does not stream video or need endpoints beyond EP0. It only has to make Windows believe it is a UVC device long enough for
usbvideo.sys to parse the configuration descriptor. One core pinned at 100% in kernel mode, USB enumeration stopped system-wide, unplugging did not recover it because the thread was stuck in driver code, and normal reboot was blocked. I reproduced this three times from a clean boot.The Teensy firmware:
- advertises a single-function USB Video Class device
- returns a valid device descriptor
- returns a configuration descriptor with one VideoControl interface
- includes a valid class-specific VC header
- appends a vendor-specific descriptor with
bLength=0
- then idles
The hang occurs during PnP start, while the driver is validating descriptors.
How do you reproduce the hang?
To reproduce, build or flash the provided firmware onto a Teensy 3.2, then plug it into a Windows system with the affected driver.
teensy_loader_cli --mcu=mk20dx256 -w -v firmware.hexOn the tested system, the result is immediate and repeatable:
- one CPU core goes to 100% in kernel mode;
- the
Systemprocess is the visible CPU consumer;
- new USB devices stop enumerating system-wide;
- unplugging the malicious device does not recover the machine;
- normal reboot uis blocked; forced reboot or power cycle required.
What can an attacker actually do with a USB denial of service?
This is a physical or malicious-peripheral denial of service. The attacker needs to present a crafted USB device to the target system. Once plugged in, the device triggers automatically during enumeration.
The stuck kernel thread can block USB enumeration across the system, so unrelated USB devices can fail to appear or recover. In a kiosk, lab, shared workstation, conference room machine, or any environment where USB ports are exposed, this is enough to require a forced reboot or power cycle to clear the condition.
The machine will not accept a keyboard, a mouse, recovery media, or forensic tooling. In addition to the camera not functioning, the denial of service also disables the response path.
Multiple malicious devices may also consume multiple cores, because each stuck enumeration path can spin independently.
Blocking USB enumeration also blocks whoever tries to fix the machine.
What did Microsoft say about the bug?
We submitted the issue to MSRC as a system-wide USB denial of service in usbvideo.sys. On July 23, 2026, MSRC responded that they did not consider it a bug and closed the case without a fix.
This submission is assessed as Not a Vulnerability and does not meet the criteria for servicing with a security update. The reported denial of service requires an attacker to physically attach a malicious USB device to the target machine, and its only effect is a local disruption that is recovered by rebooting. A locally triggered, physically-present denial of service of this kind does not meet the bar for a security vulnerability.
Timeline
2026-05-02 Issue discovered and reproduced with Teensy firmware
2026-05-02 MSRC submission prepared
2026-07-23 MSRC responded that they did not consider it a bugHow should this be fixed?
The minimal fix is to reject zero-length descriptors in the new generic validation path:
if (desc->bLength < 2)
return ERROR;
if (desc > end || end - desc < desc->bLength)
return ERROR;
This is the same class of defensive parser rule already used elsewhere in the USB stack.
Closing Thoughts
Parser progress is a security property. If a kernel parser accepts attacker-controlled length fields without proving forward progress, an untrusted device can pin kernel execution in a loop.
Delphos found this vulnerability from the binary. The platform surfaced the risky parser behavior, reconstructed the feature-flagged path, and showed why the new validation logic was suspicious. It also created the code for a PoC. The manual work was to confirm the analysis and physically help to build the hardware proof.
The bug demonstrates an input-validation regression in a kernel driver, reached by a physical USB descriptor and found without source code. This is the type of low-level behavior that traditional tooling often misses and that automated binary analysis surfaces when it understands parser progress and trusted/untrusted data flow.
We must understand opaque software before trusting it, even when the software is a signed operating-system driver. This necessitates a tool that can analyze compiled binaries.
