# CVE-2026-34343 — Windows AppID `appid.sys` Integer Truncation in `AiConvertFullImagePathToMacroFormat` → Heap Overflow

---

## Summary

| | |
|---|---|
| **Product** | Windows — `appid.sys` (Application Identity subsystem; also `srpapi.dll` / `appidapi.dll`) |
| **CVE ID** | CVE-2026-34343 |
| **Impact** | Elevation of Privilege |
| **MSRC severity** | Important |
| **CVSS** | 7.8 / 6.8 — `CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H/E:U/RL:O/RC:C` |
| **CWE** | CWE-122: Heap-based Buffer Overflow (root cause: 16-bit length truncation) |
| **Delivery** | Local — a crafted (long) image path converted to macro format |
| **KB / Fixed build** | KB5089549 — `appid.sys` 10.0.26100.8457 (Win11 24H2 x64) |
| **Patch Date** | May 12, 2026 (2026-May) |
| **Pre-patch binary** | `appid.sys` 10.0.26100.8246 — SHA256 `3fa168fc585376dfd4223579c6cd9c4b6e107be0bc645e78297296ddbac7b06f` |
| **Post-patch binary** | `appid.sys` 10.0.26100.8457 — SHA256 `e0d3b96d2be59e5fe931d543a5e2457b82a50756e7a9224868c7372ad5aaa540` |
| **Feature flag** | `Feature_3858697530` — **the fix is CFR-gated** |
| **Exploitability** | Exploitation Less Likely; not publicly disclosed; not exploited (per MSRC) |

---

## Product Description

`AiConvertFullImagePathToMacroFormat` (present in the kernel driver `appid.sys`
and the user-mode `srpapi.dll` / `appidapi.dll`) rewrites the prefix of a file
path with macro placeholders such as `%OSDRIVE%`, `%REMOVABLE%`, `%HOT%` for
AppLocker / Application Identity policy evaluation.

---

## Vulnerability Summary

The converted string length is computed as `a2->Length + prefix_len - matched_len`.
All three operands are **`USHORT`** (16-bit) `UNICODE_STRING.Length` fields.
Although C integer promotion performs the arithmetic at 32 bits, the result is
stored back into `DestinationString.Length` — again a **`USHORT`** — so it is
**truncated to the low 16 bits** (in `appid.sys` an explicit `(unsigned __int16)`
cast makes this visible).

That truncated length is then passed to `AiAlloc` as the buffer size, so a buffer
**far smaller than required** can be allocated, while the following `memmove` /
`memcpy` copy based on the **original (non-truncated)** size — a heap/pool
overflow. E.g. `a2->Length = 65000`, `prefix_len = 1000`, `matched_len = 10` needs
65,990 bytes, but truncation to 16 bits allocates only **470 bytes** → a ~64,520-byte
overflow. The defect exists in **two loops**: the macro-prefix array loop and the
global linked-list (`::P`) loop.

---

## Prerequisites and Constraints

- Local, low-privileged (`PR:L`, `AV:L`, `AC:L`): drive conversion of a crafted,
  very long image path (so `a2->Length + prefix_len - matched_len` exceeds 0xFFFF).
- The truncated length under-sizes the `AiAlloc` buffer while the copy uses the
  real length → kernel-pool / heap overflow.

---

## Vulnerability Details

### Root Cause

The length was validated/stored only at 16-bit width, so a genuinely >0xFFFF
length wrapped to a small value used for allocation, while the copy used the full
length.

### The patch (confirmed — diff, .8246 → .8457)

Gated behind `Feature_3858697530`, the fix introduces a **32-bit intermediate**
length and adds an explicit **`> 0xFFFE`** bound check before the length is stored
into the 16-bit field / used for allocation; if exceeded, conversion aborts with
**`STATUS_NAME_TOO_LONG` (`0xC0000106`)**. `0xFFFE` is the maximum valid
`UNICODE_STRING.Length`:

```c
// AiConvertFullImagePathToMacroFormat (10.0.26100.8457) — PATCHED, feature-enabled branch (from our diff)
if (Feature_3858697530__private_IsEnabledDeviceUsage()) {
    uVar3 = a2->Length + prefix_len - matched_len;     // 32-bit intermediate
    if (0xfffe < uVar3) return 0xc0000106;             // *** STATUS_NAME_TOO_LONG ***
    DestinationString.Length = (USHORT)uVar3;
}
// ... and identically in the global-list loop:
if (0xfffe < uVar8) return 0xc0000106;
```

The check is applied in **both** the macro-prefix-array loop and the global-list
loop, so an over-length value is blocked before it is truncated into the 16-bit
`Length`. The global-list error path also adds conditional cleanup: `P[1]` is
freed only when it was independently allocated (`P[1] != i[6]`), avoiding list-node
corruption.

### Patch Completeness Assessment

**CFR-gated behind `Feature_3858697530`.** The 32-bit-validated bound runs only when
the flag is enabled; the original truncating path still ships when disabled. Verify
`Feature_3858697530` is enabled to confirm the fix is live. (The same function in
`srpapi.dll` / `appidapi.dll` receives the corresponding user-mode fix.)

---

## Detection Guidance

**Behavioural.** AppLocker / AppID path-to-macro conversion of unusually long image
paths; kernel-pool / heap-corruption crashes in `appid!AiConvertFullImagePathToMacroFormat`
after `AiAlloc` on unpatched/flag-disabled builds; conversions now returning
`STATUS_NAME_TOO_LONG` for over-length paths once the fix is active.

**Config.** The fix is CFR-gated — confirm `Feature_3858697530` is enabled.

---

## References

- MSRC advisory — CVE-2026-34343 (Windows Application Identity (AppID) Subsystem Elevation of Privilege), released 2026-05-12, KB5089549.
- Full binary diff: `/data/patch_diffs/appid_sys-cve-2026-34343-ghidriff.md`
