> Windows Syscalls
ntoskrnl.exeT1553T1574T1106

NtSetCachedSigningLevel

Writes a Code Integrity cached signing-level result into an NTFS extended attribute on the target file.

Prototype

NTSTATUS NtSetCachedSigningLevel(
  ULONG              Flags,
  SE_SIGNING_LEVEL   InputSigningLevel,
  PHANDLE            SourceFiles,
  ULONG              SourceFileCount,
  HANDLE             TargetFile
);

Arguments

NameTypeDirDescription
FlagsULONGinBitmask controlling cache behaviour; 0x4 forces re-evaluation, 0x8 skips trust verification.
InputSigningLevelSE_SIGNING_LEVELinRequested signing level to stamp: 0=Unchecked, 4=Authenticode, 6=Store, 8=Antimalware, 12=Microsoft, 14=Windows.
SourceFilesPHANDLEinArray of file handles whose cached signing level should be inherited; usually NULL.
SourceFileCountULONGinNumber of entries in SourceFiles; 0 when SourceFiles is NULL.
TargetFileHANDLEinHandle to the file whose $Kernel.Purge.ESBCache extended attribute will be written.

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070x16Ewin10-1507
Win10 16070x176win10-1607
Win10 17030x17Cwin10-1703
Win10 17090x17Fwin10-1709
Win10 18030x181win10-1803
Win10 18090x182win10-1809
Win10 19030x183win10-1903
Win10 19090x183win10-1909
Win10 20040x189win10-2004
Win10 20H20x189win10-20h2
Win10 21H10x189win10-21h1
Win10 21H20x18Bwin10-21h2
Win10 22H20x18Bwin10-22h2
Win11 21H20x193win11-21h2
Win11 22H20x196win11-22h2
Win11 23H20x196win11-23h2
Win11 24H20x198win11-24h2
Server 20160x176winserver-2016
Server 20190x182winserver-2019
Server 20220x191winserver-2022
Server 20250x198winserver-2025

Kernel module

ntoskrnl.exeNtSetCachedSigningLevel

Related APIs

NtGetCachedSigningLevelWldpQueryDynamicCodeTrustSetProcessMitigationPolicy (ProcessSignaturePolicy)GetProcessMitigationPolicy

Syscall stub

4C 8B D1            mov r10, rcx
B8 98 01 00 00      mov eax, 0x198
F6 04 25 08 03 FE 7F 01   test byte ptr [0x7FFE0308], 1
75 03               jne short +3
0F 05               syscall
C3                  ret
CD 2E               int 2Eh
C3                  ret

Undocumented notes

Part of the **Code Integrity (CI)** infrastructure introduced with Windows 10. CI maintains an EA-cached signing verdict on every executable file so that subsequent image loads avoid the expensive Authenticode hash walk. The cache lives in the NTFS extended attribute `$Kernel.Purge.ESBCache` (the EA is hidden — `fsutil file queryea` won't show it by default; CI uses a private FSCTL). `NtSetCachedSigningLevel` is the *writer* — it asks CI (`ci.dll` driver inside ntoskrnl's CI module) to compute or accept a signing level and stamp it into the EA. The companion `NtGetCachedSigningLevel` is the *reader*. The privileged levels (8 Antimalware, 12 Microsoft, 14 Windows) require `SeTcbPrivilege` *and* the calling process itself to be running at an equal or higher CI level — so a normal user-mode process cannot just stamp `SE_SIGNING_LEVEL_WINDOWS`. The call became attractive to researchers because *some* of its parameter validation lives in CI policy, not in `Nt*` itself, and historical bugs in policy resolution have been used to coerce CI into accepting unsigned files.

Common malware usage

Not a commodity-malware syscall, but a recurring **research vector for sandbox escapes and CIG (Code Integrity Guard) bypasses**. James Forshaw (Project Zero) documented multiple paths where `NtSetCachedSigningLevel` could be coerced into stamping an attacker-controlled DLL with a `Microsoft`-level cache entry — sufficient to slip the DLL past a process protected with `ProcessSignaturePolicy = MicrosoftSignedOnly`. Edge/Chrome sandbox-escape PoCs (CVE-2020-0938 era and follow-ups) used this to load attacker code into the browser broker after RCE in the renderer. The Print Spooler / `Win32k` bug classes that intersect with App Container also touch this path. **Real-world malware essentially never calls this** — abuse appears in red-team / research code, **PPLFault** (Gabriel Landau, 2022), and Process-Mitigation-Policy bypasses. If you see a non-Microsoft-signed process calling `NtSetCachedSigningLevel(SE_SIGNING_LEVEL_WINDOWS)` you are looking at exploitation, not normal behaviour.

Detection opportunities

ETW `Microsoft-Windows-CodeIntegrity` provider (GUID `{4ee76bd8-3cf4-44a0-a0ac-3937643e37a3}`) emits event 3023 / 3033 on cache writes, including the requested signing level and the calling process image path. CI also logs to the Application & Services / `CodeIntegrity-Operational` channel — events 3033 (file blocked) and 3089 (signature info) reference cache lookups. The strongest signal is: any process whose own image is not signed at or above `SE_SIGNING_LEVEL_MICROSOFT` calling `NtSetCachedSigningLevel` at all, and especially with `InputSigningLevel >= 8`. Defender's `Block credential stealing from the Windows local security authority subsystem` ASR rule indirectly catches some abuse paths because the post-exploitation step usually injects into a protected process.

Direct syscall examples

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtSetCachedSigningLevel (SSN 0x198 on Win11 24H2 / Server 2025)
NtSetCachedSigningLevel PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 198h         ; SSN — drifts; resolve dynamically for portability
    syscall
    ret
NtSetCachedSigningLevel ENDP

cCIG-bypass research pattern

// Forshaw-style CI cache stamping. Requires the calling process to already
// run at SE_SIGNING_LEVEL_MICROSOFT or above — the abuse vector is *getting
// that level* via a policy resolution bug, not this call itself.
#define SE_SIGNING_LEVEL_UNCHECKED   0
#define SE_SIGNING_LEVEL_AUTHENTICODE 4
#define SE_SIGNING_LEVEL_STORE       6
#define SE_SIGNING_LEVEL_ANTIMALWARE 8
#define SE_SIGNING_LEVEL_MICROSOFT   12
#define SE_SIGNING_LEVEL_WINDOWS     14

HANDLE hFile = /* opened with FILE_READ_DATA | FILE_WRITE_EA */;
NTSTATUS st = NtSetCachedSigningLevel(
    /* Flags */              0x4,           // force recompute
    /* InputSigningLevel */  SE_SIGNING_LEVEL_MICROSOFT,
    /* SourceFiles */        NULL,
    /* SourceFileCount */    0,
    /* TargetFile */         hFile);

cRead the resulting EA with NtGetCachedSigningLevel

// Verify the cache stamp succeeded by reading it back.
ULONG  flags = 0, level = 0, thumbAlg = 0, thumbSize = 32;
BYTE   thumb[32];
LARGE_INTEGER lastBlackList = { 0 }, lastTimeStamp = { 0 };
NTSTATUS st = NtGetCachedSigningLevel(
    hFile, &flags, (PSE_SIGNING_LEVEL)&level,
    thumb, &thumbSize, &thumbAlg,
    &lastBlackList, &lastTimeStamp);
// level should now equal what NtSetCachedSigningLevel stamped, e.g. 12 (Microsoft).

MITRE ATT&CK mappings

Last verified: 2026-05-20