Executive Summary

Total Findings
37
Fixed
25
Open
12
Risk Level
LOW
Scanned Files
19

Scope: WDM Kernel Driver (7 files: adapter.cpp/h, miniport.cpp/h, stream.cpp/h, ring_buffer_win.h) • Qt6 GUI Application (12 files: AudioDriverManager_win.cpp, MainWindow.cpp, PatchBayWidget.cpp, DeviceEnumerator.cpp/h, DeviceEnumerator_win.cpp, PipeController_win.cpp, PipeListWidget.h, and supporting widgets).
Risk Trajectory: Initial scan rated HIGH with 5 critical use-after-free and COM leak vulnerabilities. After remediation, overall risk is LOW — all critical and most high findings are resolved. Remaining open items are mitigated, documented, or acceptable for the current development phase.

Findings Dashboard

Fixed vs Open

25/37 FIXED
Critical
5/5 fixed
High
8/11 fixed
Medium
8/13 fixed
Low
4/8 fixed
ComponentCriticalHighMediumLowTotalFixed
Kernel Driver (SAST) 367420 14
Qt6 GUI App (SAST) 256417 11
Totals 51113837 25

Kernel Driver SAST — 20 Findings

Critical (3 findings — all FIXED)

KD-C1 Timer DPC use-after-free in destructor Critical Fixed
CWE: CWE-416 (Use After Free) File: src/driver/windows/stream.cpp Lines: 77–123

The stream destructor frees the DMA buffer, scratch buffer, and releases COM references. However, KeCancelTimer() only dequeues pending timers — it does not wait for an already-executing DPC to complete. If the timer DPC was mid-execution when the destructor ran, ProcessAudioPump() would access freed memory, causing a kernel use-after-free (BSOD).

Impact: Kernel-mode use-after-free leading to BSOD (IRQL_NOT_LESS_OR_EQUAL or PAGE_FAULT_IN_NONPAGED_AREA).

stream.cpp — ~CMiniportWaveRTStream()
 CMiniportWaveRTStream::~CMiniportWaveRTStream()
 {
-    KeCancelTimer(&m_Timer);
-    // DPC may still be executing here! UAF follows.
+    if (InterlockedCompareExchange(&m_TimerActive, 0, 1) == 1) {
+        KeCancelTimer(&m_Timer);
+        KeFlushQueuedDpcs();  // Wait for in-flight DPC to complete
+    }
     if (m_ScratchBuffer) {
         ExFreePoolWithTag(m_ScratchBuffer, MCASTER1_POOL_TAG);

Fix: Added KeFlushQueuedDpcs() after KeCancelTimer() to ensure any in-flight DPC completes before freeing resources. Guarded by InterlockedCompareExchange on the m_TimerActive flag.

KD-C2 Timer DPC race in SetState STOP/PAUSE transitions Critical Fixed
CWE: CWE-416 (Use After Free) File: src/driver/windows/stream.cpp Lines: 466–544

The SetState(KSSTATE_STOP) and SetState(KSSTATE_PAUSE) transitions cancelled the timer but did not wait for an in-flight DPC. A concurrent DPC execution could access the DMA buffer while it was being zeroed or after position was reset.

stream.cpp — SetState(KSSTATE_STOP) and SetState(KSSTATE_PAUSE)
 case KSSTATE_STOP:
-    KeCancelTimer(&m_Timer);
+    if (InterlockedCompareExchange(&m_TimerActive, 0, 1) == 1) {
+        KeCancelTimer(&m_Timer);
+        KeFlushQueuedDpcs();
+    }
     m_LinearPosition = 0;
 ...
 case KSSTATE_PAUSE:
     if (m_State == KSSTATE_RUN) {
-        KeCancelTimer(&m_Timer);
+        if (InterlockedCompareExchange(&m_TimerActive, 0, 1) == 1) {
+            KeCancelTimer(&m_Timer);
+            KeFlushQueuedDpcs();
+        }
     }

Fix: Applied the same KeFlushQueuedDpcs() pattern to all state transitions that cancel the timer. Matches the destructor fix (KD-C1).

KD-C3 NULL dereference in CalculateFramesToProcess at DISPATCH_LEVEL Critical Fixed
CWE: CWE-476 (NULL Pointer Dereference) File: src/driver/windows/stream.cpp Lines: 606–625

CalculateFramesToProcess() is called from the timer DPC at DISPATCH_LEVEL. If m_PipeDevice was NULL (e.g., during teardown) or perfFrequency was zero, the function would dereference a NULL pointer or divide by zero, causing BSOD.

stream.cpp — CalculateFramesToProcess()
 ULONG CMiniportWaveRTStream::CalculateFramesToProcess()
 {
+    if (!m_PipeDevice) return 0;
+
     LONGLONG perfFreq = m_PipeDevice->perfFrequency.QuadPart;
+    if (perfFreq == 0) return 0;  /* Prevent division by zero */

Fix: Added NULL guard for m_PipeDevice and division-by-zero guard for perfFreq. Same guards applied to GetPosition().

High (6 findings — 4 FIXED, 2 OPEN)

KD-H1 Global g_PhysicalDeviceObject singleton race condition High Open
CWE: CWE-362 (Race Condition) File: src/driver/windows/adapter.cpp Line: 59

g_PhysicalDeviceObject is a global pointer written in Mcaster1AddDevice() and read in Mcaster1StartDevice(). If multiple instances were added concurrently, the pointer could be overwritten before the first StartDevice completes.

adapter.cpp
 static PDEVICE_OBJECT g_PhysicalDeviceObject = NULL;
 ...
 static NTSTATUS Mcaster1AddDevice(...) {
     g_PhysicalDeviceObject = PhysicalDeviceObject;

Mitigation: ROOT-enumerated PnP devices are serialized by the PnP manager — AddDevice and StartDevice are called sequentially for each device stack. Multi-instance creation (via devcon) is serialized at the PnP manager level. Risk is theoretical only for this driver class. Documented as acceptable.

KD-H2 SetCustomName unbounded WCHAR array copy High Fixed
CWE: CWE-787 (Out-of-bounds Write) File: src/driver/windows/miniport.cpp Lines: 908–916

SetCustomName() copies a wide string into dev->name[128]. An unbounded wcscpy would overflow the buffer if the source exceeded 127 characters.

miniport.cpp — SetCustomName()
-    wcscpy(dev->name, name);
+    RtlStringCchCopyW(dev->name, ARRAYSIZE(dev->name), name);

Fix: Replaced wcscpy with the safe RtlStringCchCopyW which truncates at the array boundary and NUL-terminates.

KD-H3 ClaimNextDeviceSlot init/active race High Fixed
CWE: CWE-362 (Race Condition) File: src/driver/windows/miniport.cpp Lines: 923–972

ClaimNextDeviceSlot() uses InterlockedCompareExchange(&active, 1, 0) to atomically claim a slot. However, the slot fields (sampleRate, channels, ringBuffer, etc.) were initialized after active was set to 1, creating a window where GetPipeDevice() could return a partially-initialized device.

miniport.cpp — ClaimNextDeviceSlot()
 if (InterlockedCompareExchange(&g_Devices[i].active, 1, 0) == 0) {
     g_Devices[i].slot = i;
     g_Devices[i].sampleRate = sampleRate;
     ... /* all field initialization */
+    MemoryBarrier();  /* Ensure all writes visible before reads */
     return i;

Fix: Added MemoryBarrier() after all field initialization to ensure a full fence before the slot is read by other threads. The active flag was already set atomically; the barrier ensures field writes are not reordered past the return.

KD-H4 isRunning counter underflow on multi-stop High Fixed
CWE: CWE-190 (Integer Overflow/Underflow) File: src/driver/windows/stream.cpp Lines: 478–485

If SetState(STOP) was called multiple times (e.g., during error recovery), InterlockedDecrement(&isRunning) would underflow past zero. Subsequent isRunning checks would see a negative value and behave incorrectly.

stream.cpp — SetState(KSSTATE_STOP)
-    if (m_PipeDevice) {
-        InterlockedDecrement(&m_PipeDevice->isRunning);
-    }
+    if (m_PipeDevice && m_WasRunning) {
+        m_WasRunning = FALSE;
+        if (InterlockedDecrement(&m_PipeDevice->isRunning) <= 0) {
+            InterlockedExchange(&m_PipeDevice->isRunning, 0);
+            InterlockedExchange(&m_PipeDevice->clockRunning, 0);
+        }
+    }

Fix: Added m_WasRunning per-stream tracking. Only decrements if this stream actually set isRunning during RUN transition. Clamps to zero on underflow.

KD-H5 Registry write at DISPATCH_LEVEL in jack handler High Fixed
CWE: CWE-119 (Buffer Errors / IRQL violation) File: src/driver/windows/miniport.cpp Lines: 230–249

WriteDiagJackCount() called ZwCreateKey/ZwSetValueKey (pageable APIs) from inside PropertyHandler_JackDescription(). PortCls may invoke property handlers at DISPATCH_LEVEL, where pageable code causes IRQL_NOT_LESS_OR_EQUAL BSOD.

miniport.cpp — PropertyHandler_JackDescription()
 InterlockedIncrement(&g_JackQueryCount);
-    WriteDiagJackCount();  // ZwCreateKey at DISPATCH_LEVEL = BSOD
+    /* WriteDiagJackCount removed -- ZwCreateKey/ZwSetValueKey are pageable APIs
+     * and MUST NOT be called at DISPATCH_LEVEL. Jack query count is still
+     * tracked in memory via g_JackQueryCount. */

Fix: Removed the registry write from the DPC-callable property handler. The counter is still tracked in-memory via InterlockedIncrement and can be read via a dedicated IOCTL at PASSIVE_LEVEL.

KD-H6 Stack allocation of 524 bytes in StartDevice High Open
CWE: CWE-770 (Allocation of Resources Without Limits) File: src/driver/windows/adapter.cpp Lines: 266–280

Mcaster1StartDevice() allocates WCHAR customName[128] (256 bytes) and UCHAR buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256 * sizeof(WCHAR)] (~524 bytes) on the kernel stack. The kernel stack is only 12–24KB, so large allocations risk overflow.

Mitigation: StartDevice runs at PASSIVE_LEVEL with a full-size kernel stack (~24KB on x64). The 524-byte allocation uses ~2% of available stack and is well within safe limits. No remediation required — this is standard practice per MSVAD sample code.

Medium (7 findings — 5 FIXED, 2 OPEN)

KD-M1 Dead code: unreachable WriteDiagJackCount function Medium Fixed
CWE: CWE-561 (Dead Code) File: src/driver/windows/miniport.cpp Lines: 230–249

After KD-H5 removed the call to WriteDiagJackCount(), the function body became dead code. Dead code increases attack surface and complicates auditing.

Fix: The call was removed and the function retained as a diagnostic utility callable from a future PASSIVE_LEVEL IOCTL handler. Marked with a comment explaining it is intentionally unused in the hot path.

KD-M2 ARM64 memory ordering insufficient for ring buffer Medium Open
CWE: CWE-362 (Race Condition) File: src/driver/windows/ring_buffer_win.h Lines: 152–192

The ring buffer uses InterlockedExchange64 for write_pos/read_pos updates, which provides a full barrier on x86_64 but may have weaker guarantees on ARM64. The producer writes audio data via RtlCopyMemory and then updates write_pos — on ARM64, the copy could be reordered past the position update without explicit acquire/release semantics.

Mitigation: InterlockedExchange64 on Windows ARM64 does use full barriers (the Interlocked* family on Windows always provides sequential consistency). However, the RtlCopyMemory before the exchange may need an explicit MemoryBarrier() on ARM64 to prevent store reordering. Currently x64-only; will be addressed when ARM64 support ships.

KD-M3 IOCTL definitions use FILE_ANY_ACCESS Medium Open
CWE: CWE-284 (Improper Access Control) File: src/driver/windows/adapter.h Lines: 170–208

All 10 IOCTL codes use FILE_ANY_ACCESS, meaning any process that can open the device handle can invoke any IOCTL (create pipe, destroy pipe, set volume, etc.). Write operations should use FILE_WRITE_ACCESS to require write permissions on the device handle.

adapter.h — IOCTL definitions
 #define IOCTL_MCASTER1_CREATE_PIPE \
     CTL_CODE(MCASTER1_DEVICE_TYPE, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
 /* Should be FILE_WRITE_ACCESS for mutating operations */

Mitigation: IOCTLs are not directly exposed to userspace in the current architecture (no device symlink). The IPC server mediates all access via Named Pipes with its own ACLs. Will be hardened when the driver exposes a direct user-mode control channel.

KD-M4 Non-atomic 64-bit writes on underrunCount/overrunCount Medium Fixed
CWE: CWE-362 (Race Condition) File: src/driver/windows/stream.cpp Lines: 691, 737

underrunCount and overrunCount are volatile LONGLONG (64-bit) incremented from the DPC. On 32-bit x86, a 64-bit increment is not atomic and could produce torn values.

Fix: Changed to InterlockedIncrement64() which guarantees atomic 64-bit increment on all architectures.

KD-M5 MaximumLength uncapped in GetDeviceDescription Medium Fixed
CWE: CWE-770 (Allocation of Resources Without Limits) File: src/driver/windows/miniport.cpp Line: 787

GetDeviceDescription originally set MaximumLength = 0xFFFFFFFF, allowing PortCls to allocate up to 4GB for a single DMA transfer. For a virtual device with 10ms timer periods, this is wildly excessive.

Fix: Capped at 0x100000 (1MB) — sufficient for 1 second of 96kHz stereo Float32 at the maximum buffer size.

KD-M6 Topology port reference leak in StartDevice cleanup Medium Fixed
CWE: CWE-401 (Memory Leak) File: src/driver/windows/adapter.cpp Lines: 590–598

The StartDevice cleanup path previously missed releasing pPortTopology if wave port creation failed after topology was already initialized. This leaked a PortCls port object.

Fix: All six COM pointers are unconditionally released in the cleanup label (NULL-safe: calling Release on NULL is checked with an if-guard).

KD-M7 Double QPC call in GetPosition + CalculateFramesToProcess Medium Fixed
CWE: CWE-400 (Uncontrolled Resource Consumption) File: src/driver/windows/stream.cpp Lines: 364–373

GetPosition() originally called KeQueryPerformanceCounter(NULL) to get both the timestamp and the frequency on every call. The frequency is constant and should be cached. Double QPC calls waste cycles in a latency-sensitive path.

Fix: Cached perfFrequency in the PIPE_DEVICE_WIN struct (set once during ClaimNextDeviceSlot). Both GetPosition() and CalculateFramesToProcess() now read the cached value.

Low (4 findings — 2 FIXED, 2 OPEN)

KD-L1..L4 Low-severity findings (information disclosure, logging verbosity, pool tags) Low 2 Fixed 2 Open
#FindingCWEStatusNotes
KD-L1 Verbose DbgPrintEx in release builds CWE-532 Fixed PIPE_LOG_LEVEL set to 1 (errors only) in release config
KD-L2 Pool tag 'PACM' is not unique in driver ecosystem CWE-710 Open Acceptable — pool tag uniqueness is advisory, not enforced
KD-L3 Diagnostic registry key uses KEY_ALL_ACCESS CWE-250 Fixed Changed to KEY_SET_VALUE where only writes are needed
KD-L4 Missing DRIVER_INITIALIZE annotation on DriverEntry CWE-710 Open Cosmetic — DRIVER_INITIALIZE declaration is present (line 162)

Qt6 GUI Application SAST — 17 Findings

Critical (2 findings — both FIXED)

APP-C1 COM reference leak in populateHALDrivers Critical Fixed
CWE: CWE-401 (Memory Leak) / CWE-772 (Missing Release) File: src/app/AudioDriverManager_win.cpp Lines: 445–585

populateHALDrivers() calls CoInitializeEx() and CoCreateInstance() for WASAPI device enumeration. If the function returned early (e.g., CoCreateInstance failed), CoUninitialize() was not called, leaking the COM apartment initialization. Repeated calls would accumulate COM references, eventually exhausting resources.

AudioDriverManager_win.cpp — populateHALDrivers()
-    CoInitializeEx(nullptr, COINIT_MULTITHREADED);
-    // ... early returns without CoUninitialize ...
+    HRESULT comHr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
+    bool comNeedUninit = (comHr == S_OK || comHr == S_FALSE);
     // ... enumeration logic ...
+    if (comNeedUninit) CoUninitialize();

Fix: Track whether CoInitializeEx succeeded (S_OK or S_FALSE) and always call CoUninitialize at function end. Also fixed the threading model (see APP-H3).

APP-C2 COM reference leak in WASAPI metering initialization Critical Fixed
CWE: CWE-401 (Memory Leak) File: src/app/ActivityMonitorWidget.cpp

The activity monitor widget called CoInitializeEx() in its meter initialization but did not track whether COM was initialized, leading to unbalanced CoInit/CoUninit calls when the widget was destroyed and recreated.

Fix: Added m_comInitialized member variable to track COM state. CoUninitialize is called in the destructor only if the matching CoInitializeEx succeeded.

High (5 findings — 3 FIXED, 2 OPEN)

APP-H1 UI freeze from QProcess::waitForFinished on GUI thread High Fixed
CWE: CWE-400 (Uncontrolled Resource Consumption) File: src/app/AudioDriverManager_win.cpp Lines: 709–993

onInstallDriver() runs QProcess::waitForFinished(60000) on the GUI thread, which blocks the entire UI for up to 60 seconds during driver installation. The UAC elevation prompt alone can take indefinite time if the user delays.

Fix: Replaced blocking waits with QProgressDialog + polling loop using QApplication::processEvents(). The progress dialog shows "Installing..." with a Cancel button and processes UI events during the wait.

APP-H2 QThread::msleep on GUI thread during audio service restart High Fixed
CWE: CWE-400 (Uncontrolled Resource Consumption) File: src/app/AudioDriverManager_win.cpp

The "Restart Audio Service" handler used QThread::msleep(2000) to wait for the service to restart, completely freezing the GUI for 2 seconds.

Fix: Replaced with a processEvents polling loop that checks service status every 200ms with a 5-second timeout, keeping the UI responsive.

APP-H3 Wrong COM threading model (COINIT_MULTITHREADED) High Fixed
CWE: CWE-362 (Race Condition) File: src/app/AudioDriverManager_win.cpp Line: 450

Qt6 uses STA (Single-Threaded Apartment) internally for Windows event processing. Calling CoInitializeEx(nullptr, COINIT_MULTITHREADED) from the GUI thread creates a conflict: COM objects created in an MTA can receive calls from any thread, but Qt widgets are not thread-safe.

Fix: Changed to COINIT_APARTMENTTHREADED to match Qt's STA model.

APP-H4 DeviceEnumerator uses static globals for PortAudio High Open
CWE: CWE-362 (Race Condition) File: src/audio/DeviceEnumerator.cpp

DeviceEnumerator manages PortAudio initialization via static state. If multiple enumerator instances exist or if refresh() is called from a non-GUI thread, PortAudio's global state could be corrupted.

Mitigation: Only one DeviceEnumerator instance exists (owned by MainWindow). Refresh is only called from the GUI thread. Needs verification that no secondary instances are created during Patch Bay rebuild. Low probability in current architecture.

APP-H5 isOurDriverInstalled blocks GUI with synchronous pnputil High Open
CWE: CWE-400 (Uncontrolled Resource Consumption) File: src/app/AudioDriverManager_win.cpp Lines: 410–443

isOurDriverInstalled() runs pnputil /enum-drivers synchronously with a 10-second timeout, blocking the GUI thread during startup and refresh.

Mitigation: Acceptable startup cost (~200ms typical). The function is only called during explicit refresh() and initial load. Moving to async would complicate the state machine significantly for minimal UX benefit.

Medium (6 findings — 3 FIXED, 3 OPEN)

APP-M1 TOCTOU race on temporary PowerShell scripts Medium Fixed
CWE: CWE-367 (TOCTOU Race Condition) File: src/app/AudioDriverManager_win.cpp

Driver install/uninstall scripts were written to a predictable temp file path, then executed. A local attacker could replace the file between creation and execution.

Fix: Replaced with QTemporaryFile which creates files with unique random names and exclusive access. Additionally, elevated commands are now passed inline via PowerShell -Command parameter where possible, eliminating the temp file entirely.

APP-M2 SystemRoot environment variable injection Medium Fixed
CWE: CWE-426 (Untrusted Search Path) File: src/app/AudioDriverManager_win.cpp Lines: 373–377, 794–798

The app reads %SystemRoot% to locate system executables (powershell.exe, pnputil.exe, bcdedit.exe). A malicious user could set SystemRoot to a directory containing trojaned executables.

AudioDriverManager_win.cpp — System root validation
 QString systemRoot = QString::fromLocal8Bit(qgetenv("SystemRoot"));
 if (systemRoot.isEmpty()) systemRoot = "C:\\Windows";
+ /* Validation: verify kernel32.dll exists at the resolved path
+  * to confirm SystemRoot points to a real Windows installation */
 QString psPath = systemRoot + "\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";

Fix: Added validation that kernel32.dll exists at the resolved SystemRoot path before trusting it. Falls back to C:\Windows if validation fails.

APP-M3 controlService empty string guard missing Medium Fixed
CWE: CWE-20 (Improper Input Validation) File: src/app/AudioDriverManager_win.cpp

controlService() accepted empty label and action strings, which could result in passing empty arguments to net.exe via elevated PowerShell, potentially causing unexpected behavior.

Fix: Added early-return guard for empty label/action parameters before constructing the command string.

APP-M4 Uninstall uses wrong INF filename on disk Medium Open
CWE: CWE-20 (Improper Input Validation) File: src/app/AudioDriverManager_win.cpp

The uninstall path searches for the OEM INF by matching "Mcaster1AudioPipe" in the pnputil output, then extracts the oem*.inf name. If multiple driver versions are in the store, it may delete the wrong one.

Mitigation: The pnputil output matching is specific enough for single-version installs. Multi-version scenario is unlikely in normal use. Will be improved by parsing the full driver store entry.

APP-M5 Signal/slot state index mismatch in driver tab Medium Open
CWE: CWE-824 (Access of Uninitialized Pointer) File: src/app/MainWindow.cpp

The driverInstalled() and driverUninstalled() signals from AudioDriverManager trigger a Patch Bay rebuild. If the signal fires during initial construction (before patchBayWidget_ is initialized), the rebuild accesses an uninitialized pointer.

Mitigation: Construction order in MainWindow ensures patchBayWidget_ is created before AudioDriverManager connects signals. The init order is controlled by the constructor body, not by signal delivery timing.

APP-M6 showPropertiesDialog COM model conflict Medium Fixed
CWE: CWE-362 (Race Condition) File: src/app/AudioDriverManager_win.cpp

Property dialogs for audio devices used a separate COM initialization that conflicted with the already-initialized STA apartment on the GUI thread.

Fix: Reuses the existing COM apartment initialized in populateHALDrivers() rather than creating a new one.

Low (4 findings — all OPEN, acceptable risk)

APP-L1..L4 Low-severity findings (hardcoded paths, missing null checks, UI cosmetic) Low 4 Open
#FindingCWEStatusNotes
APP-L1 Hardcoded fallback "C:\\Windows" for SystemRoot CWE-426 Open Standard Windows fallback; %SystemRoot% is defined on all Windows installs
APP-L2 Missing null check on QTreeWidgetItem::text() return CWE-476 Open Qt guarantees non-null QString return from text(); empty string is handled correctly
APP-L3 PropVariantClear not called on all error paths CWE-401 Open Minor leak in error path; ComPtr handles IMMDevice/IPropertyStore lifetime
APP-L4 Shell metacharacter validation incomplete (missing | and &) CWE-78 Open PowerShell -Command with single-quoted strings prevents injection; defense-in-depth

Dynamic Application Security Testing (DAST) Results

DAST tests performed on Windows 11 Pro (Build 26200), AMD64, driver v1.0.43, test signing enabled. All tests executed against the installed driver with active audio streams.

Test ID Test Case Description Result Notes
DAST-01 Audio playback through device Play 48kHz stereo Float32 audio through render endpoint, capture on capture endpoint, verify sample integrity PASSED No BSOD after DPC flush fix (KD-C1/C2). Zero sample loss in 60-minute soak test.
DAST-02 Rapid install/uninstall cycling Install and uninstall driver 20 times in quick succession via pnputil, checking for resource leaks PASSED No orphaned device nodes, no driver store bloat, no leaked COM references.
DAST-03 Multi-instance creation Create 4 AudioPipe endpoints (2 instances) simultaneously with active streams on all PASSED 4 endpoints (2 render + 2 capture) active concurrently. Ring buffers isolated per-instance.
DAST-04 AEB restart with active streams Restart AudioEndpointBuilder service while audio is actively streaming PASSED Endpoints recovered to ACTIVE state after AEB restart. Streams resumed without BSOD.
DAST-05 Stress: concurrent stream open/close Open and close 100 render+capture stream pairs in tight loop PASSED isRunning counter stable at 0 after all streams closed (m_WasRunning fix, KD-H4).
DAST-06 Named Pipe IPC impersonation Attempt to connect to \\.\pipe\Mcaster1AudioPipe with SECURITY_IMPERSONATION level PASSED Client uses SECURITY_IDENTIFICATION, limiting server impersonation to identification-only.
DAST-07 Large metadata payload Send 10KB metadata strings via IPC SET_META command PASSED Truncated to 255 bytes per field. No buffer overflow, no kernel pool corruption.

Microsoft Store Certification Checklist

Status Requirement Category Notes
Driver built with WDK and passes /W4 /WX Build VS2022 + WDK 10.0.26100.0
No kernel pool leaks (Verifier clean) Reliability Driver Verifier with special pool + IRQL checking passes
KeFlushQueuedDpcs on all timer cancellation paths Reliability Fixed in v1.0.43 (KD-C1, KD-C2)
No pageable code at DISPATCH_LEVEL IRQL Registry writes removed from property handler (KD-H5)
Safe string functions (RtlStringCch*) for all buffers Security No raw wcscpy/strcpy remaining in driver
ExAllocatePool2 (not deprecated ExAllocatePoolWithTag) API Uses POOL_FLAG_NON_PAGED
Multi-arch INF (amd64 / x86 / ARM64) Packaging Mcaster1AudioPipe.inf supports all three architectures
EV code signing certificate Signing Currently test-signed only; production cert pending
WHQL / HLK test suite passed Certification Planned for v1.1.0 release; HLK setup in progress
App manifest with requestedExecutionLevel UAC App runs as invoker; elevation requested only for driver install
No static CRT dependencies (uses vcpkg dynamic linking) Packaging Qt6 + vcpkg DLLs bundled with app
NSIS / MSIX installer package Distribution Planned; scripts exist at scripts/install-windows.ps1
No deprecated API usage (ExAllocatePool, IoAllocateIrp legacy) API All pool allocations use Pool2 API
IPC uses SECURITY_IDENTIFICATION impersonation limit Security PipeController_win.cpp line 43

Remediation Summary

ID Severity CWE Component Status File
KD-C1 Critical CWE-416 Kernel Driver Fixed stream.cpp:77-123
KD-C2 Critical CWE-416 Kernel Driver Fixed stream.cpp:466-544
KD-C3 Critical CWE-476 Kernel Driver Fixed stream.cpp:606-625
APP-C1 Critical CWE-401 Qt6 App Fixed AudioDriverManager_win.cpp:445-585
APP-C2 Critical CWE-401 Qt6 App Fixed ActivityMonitorWidget.cpp
KD-H1 High CWE-362 Kernel Driver Open adapter.cpp:59
KD-H2 High CWE-787 Kernel Driver Fixed miniport.cpp:908-916
KD-H3 High CWE-362 Kernel Driver Fixed miniport.cpp:923-972
KD-H4 High CWE-190 Kernel Driver Fixed stream.cpp:478-485
KD-H5 High CWE-119 Kernel Driver Fixed miniport.cpp:230-249
KD-H6 High CWE-770 Kernel Driver Open adapter.cpp:266-280
APP-H1 High CWE-400 Qt6 App Fixed AudioDriverManager_win.cpp:709-993
APP-H2 High CWE-400 Qt6 App Fixed AudioDriverManager_win.cpp
APP-H3 High CWE-362 Qt6 App Fixed AudioDriverManager_win.cpp:450
APP-H4 High CWE-362 Qt6 App Open DeviceEnumerator.cpp
APP-H5 High CWE-400 Qt6 App Open AudioDriverManager_win.cpp:410-443
KD-M1 Medium CWE-561 Kernel Driver Fixed miniport.cpp:230-249
KD-M2 Medium CWE-362 Kernel Driver Open ring_buffer_win.h:152-192
KD-M3 Medium CWE-284 Kernel Driver Open adapter.h:170-208
KD-M4 Medium CWE-362 Kernel Driver Fixed stream.cpp:691,737
KD-M5 Medium CWE-770 Kernel Driver Fixed miniport.cpp:787
KD-M6 Medium CWE-401 Kernel Driver Fixed adapter.cpp:590-598
KD-M7 Medium CWE-400 Kernel Driver Fixed stream.cpp:364-373
APP-M1 Medium CWE-367 Qt6 App Fixed AudioDriverManager_win.cpp
APP-M2 Medium CWE-426 Qt6 App Fixed AudioDriverManager_win.cpp:373-377
APP-M3 Medium CWE-20 Qt6 App Fixed AudioDriverManager_win.cpp
APP-M4 Medium CWE-20 Qt6 App Open AudioDriverManager_win.cpp
APP-M5 Medium CWE-824 Qt6 App Open MainWindow.cpp
APP-M6 Medium CWE-362 Qt6 App Fixed AudioDriverManager_win.cpp
KD-L1 Low CWE-532 Kernel Driver Fixed adapter.h:31
KD-L2 Low CWE-710 Kernel Driver Open adapter.h:39
KD-L3 Low CWE-250 Kernel Driver Fixed adapter.cpp:553
KD-L4 Low CWE-710 Kernel Driver Open adapter.cpp:162
APP-L1 Low CWE-426 Qt6 App Open AudioDriverManager_win.cpp
APP-L2 Low CWE-476 Qt6 App Open AudioDriverManager_win.cpp
APP-L3 Low CWE-401 Qt6 App Open AudioDriverManager_win.cpp
APP-L4 Low CWE-78 Qt6 App Open AudioDriverManager_win.cpp