RegPwn: How CVE-2026-24291 Reaches SYSTEM

Thanks are due to Filip Dragovic and MDSec for publishing the initial public technical write-up that made this issue mechanically understandable rather than leaving it at the advisory shorthand of an incorrect permission assignment. Their advisory, research, and initial write-up, RIP RegPwn, is here.

Microsoft’s advisory for CVE-2026-24291 is here.

CVE-2026-24291 was published by Microsoft on 10 March 2026 as a local elevation of privilege flaw in Windows Accessibility Infrastructure. The public description is directionally correct, but on its own it does not explain where the trust boundary is crossed, why the useful write occurs as SYSTEM, or why the behaviour is exploitable rather than merely untidy. MDSec’s research matters because it exposes the actual execution path rather than stopping at the headline.

The important point is that this is not simply a case of an accessibility feature running on the secure desktop. Windows already has a documented model for carrying assistive technology state from the normal desktop into secure desktop contexts. The issue sits in the hand-off between those worlds. User-controlled configuration is staged through a session-scoped registry location that remains writable to the logged-in user, and a privileged component later writes through that location during secure desktop initialisation. Once that sequence is understood, the exploit path becomes much easier to reason about.

Accessibility registration and secure desktop state

Microsoft documents an explicit registration model for assistive technologies. Accessibility applications are registered under the ATs branch, and CopySettingsToLockedDesktop is the switch that allows an application to persist state from the normal desktop into the locked or secure desktop. Microsoft also documents the per-user configuration path used for that state.

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Accessibility\ATs
HKCU\Software\Microsoft\Windows NT\CurrentVersion\Accessibility\ATConfig\<AT Key Name>

If CopySettingsToLockedDesktop is set to 1, Windows copies settings from that HKCU location to the same location in the secure desktop’s HKCU hive. Microsoft’s documentation is explicit that the Ease of Access infrastructure monitors this registry location while the application is running and copies the settings when a transition to the secure desktop occurs. It also notes that these keys are written in user mode and are not secure. That warning is useful context, because it shows that this state is already treated as inherently untrusted user data.

Microsoft’s UAC documentation also states that consent and credential prompts are shown on the secure desktop by default, and that only Windows processes can access it. Separately, Microsoft’s assistive technology security documentation explains that UIAccess is intended to let accessibility software interact across integrity boundaries, but that this does not by itself grant access to system integrity UI. Access to UI running under system integrity occurs only when a process is launched on the UAC desktop under SYSTEM. That distinction matters later, because it helps separate background platform context from the actual privilege escalation mechanism.

The implementation path that matters

The implementation path for osk is more concrete than the public documentation suggests. The normal per-user settings live under the expected HKCU branch, but Windows then stages those values into a session-scoped key under HKLM that is created during logon and, critically, is writable by the logged-in user. Below is the observed the following path for that staging area.

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Accessibility\Session<session id>\ATConfig\osk

From there, Observed is a second copy into the hive used by the secure desktop context. In their testing, that destination was the following path.

HKU\.DEFAULT\Software\Microsoft\Windows NT\CurrentVersion\Accessibility\ATConfig\osk

Finally, when the secure desktop instance of osk.exe starts as SYSTEM, it copies values back out of HKU\.DEFAULT into the same session-scoped HKLM path. That last step is what turns a configuration copy into a privileged primitive, because the destination key is still writable and replaceable by the user at precisely the wrong moment.

The sequence below is illustrative pseudocode rather than verbatim implementation, but it captures the trust flow that matters.

copy_user_settings(
L"HKCU\\...\\Accessibility\\ATConfig\\osk",
L"HKLM\\...\\Accessibility\\Session<id>\\ATConfig\\osk"
);

if (secure_desktop_transition) {
copy_system_settings(
L"HKLM\\...\\Accessibility\\Session<id>\\ATConfig\\osk",
L"HKU\\.DEFAULT\\...\\Accessibility\\ATConfig\\osk"
    );

copy_system_settings(
L"HKU\\.DEFAULT\\...\\Accessibility\\ATConfig\\osk",
L"HKLM\\...\\Accessibility\\Session<id>\\ATConfig\\osk"
    );
}

The first copy is not the dangerous one. The second and third copies are the interesting part, because they happen across the secure desktop boundary and involve SYSTEM processes. The vulnerable behaviour is not that Windows copies accessibility settings. The vulnerable behaviour is that Windows later performs a privileged write through a user-influenceable registry path.

Root cause: A writable staging key becomes a privileged write sink

At a high level, the flaw is a confused trust model around a staging location. The session key sits under HKLM, which makes it look system-scoped, but it is observed that it is created during the logon process with write privileges for the logged-in user. Later, when the secure desktop transition occurs, privileged components treat that same location as part of a trusted state propagation path. That is the actual boundary failure.

A naive reading would be that the problem is the original HKCU settings path. It is not. User-controlled configuration in HKCU is expected. The bug is that Windows copies that state into a writable intermediary and then later performs a SYSTEM write through the intermediary as though it were stable and trustworthy. That distinction matters because it explains both the exploit and the likely fix direction. The flaw is not that the user can set accessibility preferences. The flaw is that a privileged writer later trusts a path the user can still reshape.

Why registry symbolic links change the outcome

It is observed as abusing the privileged write with a registry symbolic link. Microsoft’s registry protocol documentation explains how these links behave. A source key created with REG_OPTION_CREATE_LINK contains a SymbolicLinkValue of type REG_LINK, and unless the caller explicitly opens the key with REG_OPTION_OPEN_LINK, opening the source key resolves transparently to the target key. That behaviour is what turns a write to one path into a write somewhere else.

The relevant semantics are easier to see in a minimal illustrative example. This is not the official exploit code, but it reflects the Windows registry link model.

RegCreateKeyExW(
hRoot,
L"SessionLink",
0,
NULL,
REG_OPTION_CREATE_LINK,
KEY_ALL_ACCESS,
NULL,
&hKey,
NULL
);

RegSetValueExW(
hKey,
L"SymbolicLinkValue",
0,
REG_LINK,
    (BYTE*)targetPath,
targetPathBytes
);

Once the writable session key is replaced with a registry link, a privileged process that believes it is writing to HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Accessibility\Session<id>\ATConfig\osk can instead be made to write to an attacker-chosen registry destination. That is why the impact is best described as an arbitrary registry write as SYSTEM, not as direct arbitrary code execution. Code execution comes later, if the attacker points that write at a security-sensitive location such as a service configuration.

Why the trigger happens during secure desktop transition

A trigger is not ordinary post-launch interaction with the on-screen keyboard. The trigger is the secure desktop transition itself. Their write-up shows that locking the workstation or creating a secure desktop through a Run as administrator path starts two atbroker.exe processes, one in the current user context and one as SYSTEM, after which the privileged copy sequence occurs and osk.exe starts on the secure desktop as SYSTEM.

This is also why a later, more casual interaction does not represent the same primitive. The exploitable operation is not any moment in which osk.exe touches its settings. It is the specific initialisation window in which secure desktop state is being materialised and copied by privileged components. That is why the exploit is timing-sensitive and why it synchronises against osk.exe start-up rather than against some later user action.

Why the oplock is there

To win the small window between osk.exe starting and the registry write occurring, the exploit places an opportunistic lock on C:\Program Files\Common Files\microsoft shared\ink\fsdefinitions\oskmenu.xml. Microsoft documents opportunistic locks as file-system coordination primitives used for notification and coherency. In this case the oplock is not the root cause and not the privileged primitive. It is a timing aid.

The important point is that the exploit does not depend on a bug in oskmenu.xml, and it is not exploiting opportunistic locks themselves. The oplock is simply used to make the race practical by giving the attacker a reliable signal that the privileged osk.exe instance is reaching the relevant start-up path, at which point the writable session key can be swapped for a registry symbolic link just before the SYSTEM write lands.

Delivery mechanism, trigger point, execution boundary, and impact

It helps to separate the moving parts clearly.

The delivery mechanism is ordinary attacker-controlled data in user-writable accessibility configuration. The attacker populates HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Accessibility\ATConfig\osk, which is expected user state rather than a privileged object.

The root cause is that Windows stages that data through HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Accessibility\Session<session id>\ATConfig\osk, even though that path remains writable to the logged-in user and later participates in a privileged secure desktop state transfer.

The trigger point is the secure desktop transition. At that point, atbroker.exe and then osk.exe running as SYSTEM perform the copy sequence across the desktop boundary.

The execution boundary crossed by the vulnerability is therefore not immediate code execution but an arbitrary registry write as SYSTEM, achieved by replacing the session key with a registry symbolic link.

The impact demonstrated comes afterwards. Their proof of concept turns that registry write into code execution by overwriting the ImagePath of the msiserver service and then starting the service through an MSI-related COM activation path.

That separation matters because it avoids a common analytical mistake. The vulnerability is not that ATBroker.exe directly gives arbitrary code execution. The vulnerability gives a privileged registry write. Code execution follows only because other privileged Windows components later consume attacker-controlled values from security-sensitive locations.

Why the intuitive reading is wrong

The intuitive reading is that the secure desktop directly trusts HKCU, or that UIAccess somehow becomes SYSTEM. Neither explanation is correct.

The more precise explanation is narrower and more useful. Windows copies legitimate user configuration into a session-scoped system location, but that location remains writable long enough for an attacker to redirect it. The vulnerability is therefore in the hand-off, not in the existence of accessibility settings, not in the secure desktop concept, and not in registry symbolic links as a feature. It is the combination that fails: writable staging state plus later privileged copy plus transparent link resolution.

That is also why the issue is easier to understand once the trust boundary is described in terms of state propagation rather than process names. The interesting question is not which binary appears in the advisory. The interesting question is which path is writable, who can still alter it, and which later privileged operation assumes it is stable.

Operational meaning

Operationally, this is a strong local post-compromise primitive. NVD scores the issue as local attack vector, low attack complexity, low privileges required, and no user interaction. Also noted is that the vulnerability had already been used successfully in red team engagements before disclosure.

The issue affected Windows 10 and 11 as well as multiple Windows Server generations. Their public repository lists tested versions including Windows 10 21H2, Windows 11 24H2 and 25H2, and Windows Server 2016, 2019, and 2022. That distinction is worth keeping in mind. Publicly reported impact and publicly tested versions are related, but they are not the same claim.

For defenders, the main point is not that this is remotely reachable or pre-authentication. It is not. Its value is that it converts an authenticated foothold into SYSTEM through a built-in Windows workflow, using a boundary that exists specifically to preserve usability across lock and elevation transitions. That makes it relevant anywhere local code execution by a low-privilege user is in scope, especially on shared systems, jump hosts, VDI environments, or servers where a limited foothold is not yet equivalent to full local control.

Conclusion

RegPwn is a good example of why an advisory phrase such as incorrect permission assignment is often too vague to be useful on its own. The interesting question is always which resource is assigned incorrectly, who can still change it, and which later privileged operation assumes it is stable. In CVE-2026-24291, the answer is a session-scoped accessibility configuration key under HKLM that remains writable to the logged-in user and is then reused during secure desktop state transfer by SYSTEM components.

The mechanism is therefore not mysterious. User configuration is staged. Secure desktop transition begins. A privileged writer reuses attacker-influenceable state. A registry link changes where the write lands. A secondary system component consumes that new value and turns it into code execution. Once broken down that way, the bug stops looking like an exotic accessibility edge case and starts looking like a classic trust-boundary failure in state propagation.