
Executive Summary
Active Directory is still the control plane of most enterprises, and Domain Admin is still the prize. Defenders spend enormous effort keeping privileged credentials out of attacker hands — but credentials are only half the story. If a domain controller can be made to mistake one identity for another, the attacker never needs to steal anything. Semperis researcher Shai Laron started from a curiosity — invisible Unicode characters in AD object names, presented by Yossi Sassi as a persistence trick — and ended up with two new Microsoft-assigned vulnerabilities that turn naming confusion into real impact: KerberLoss (CVE-2026-25177) and ResetNightmare (CVE-2026-27912).
KerberLoss exploits a gap between what Active Directory’s uniqueness checks compare and what the LDAP server can actually filter on: a set of Unicode characters that the DC silently ignores. Slipping one of those characters into a Service Principal Name defeats the SPN and SPN-alias uniqueness verification introduced by the CVE-2021-42282 patch, which yields a forest-wide denial of service against any HOST-mapped service, an improved variant of Elad Shamir’s SPN-jacking that no longer needs WriteSPN on the intermediate host, and a reliable way to force any service in the forest to fall back from Kerberos to NTLM. ResetNightmare is the more serious of the two: by setting a low-privileged account’s UPN to a Domain Admin’s SamAccountName and requesting a TGT with the NT-ENTERPRISE name type, an attacker gets a ticket bearing the admin’s name — and because the Kerberos Change Password protocol goes straight from AS-REQ to AP-REQ, it never passes through the TGS exchange where the PAC_REQUESTOR_SID validation from the CVE-2021-42287 patch happens. The result is an instant password reset of a Domain Admin from generic Write permissions on a single object. Microsoft patched KerberLoss in March 2026 and ResetNightmare in April 2026.
The research began with a talk. Yossi Sassi, speaking about Active Directory persistence, demonstrated something the author had not seen before: “invisible” Unicode characters can be embedded in object attributes, producing accounts that look identical to legitimate ones. As a persistence technique it is effective precisely because it wastes an investigator’s time — two objects on screen, indistinguishable, one of them planted.
That raised three questions worth chasing:
- Does Active Directory accept “invisible” characters other than the handful already known?
- How could abuse of those characters be detected efficiently, at scale?
- Do hidden characters have uses beyond persistence?
The answer to the third question turned out to be the interesting one.
Initial research: Unicode and Active Directory
The questions led into a rabbit hole about Unicode and server-side LDAP processing. The first step was mechanical: sweep the web for Unicode code points that render as nothing, and collect them into a list. The characters of interest were specifically those that stay invisible inside object names, since that is where the confusion is most useful.
Testing started with a sample account named UniqueUser. Creating a second account with the same name fails, exactly as you would expect (Figure 1).

Insert one “invisible” character, however, and an apparently identical account is created without complaint (Figure 2).

The PowerShell console renders the result with a strange gap before “ser” — a small tell, and one that only shows up in a terminal. Open the same two accounts in the graphical AD management tools and they are indistinguishable (Figure 3).

With the method established, the whole candidate list was iterated: one user account per character. Some of the characters turned out not to be invisible at all once Active Directory got hold of them (Figure 4).

Pruning those left a much cleaner directory (Figure 5).

Two different kinds of failure showed up during the sweep. Some characters the DC simply refused. Others were skipped because the DC insisted the username already existed — which, in hindsight, was the entire research foreshadowing itself. To get around the uniqueness constraint and test as many characters as possible, a second batch of accounts was created, each name carrying one candidate character sandwiched between two dashes (Figure 6).

The end state was a working list of 385 invisible characters — question one answered. Time to look at detection.
A different detection approach
Sassi’s original talk shipped a detection tool, and it is worth understanding how it works. The script takes a straightforward client-side approach:
- Create a dictionary of 29 “invisible” characters.
- Get all properties of all objects in the domain.
- Iterate through each attribute.
- Convert the attribute to an array of characters.
- Retrieve the hex value of each character and compare it against the dictionary.
That is comprehensive, and comprehensiveness has a cost: pulling every attribute of every object and walking it character by character is not something you want running routinely against a production forest. The natural question is whether the filtering can be pushed into the LDAP request itself — evaluated server-side rather than reconstructed on the client.
The first test was the simplest one possible: can the DC process these characters as-is? Character 0x200B was converted to its invisible string form, then pasted straight into a PowerShell LDAP filter (Figure 7).

That worked: the filter returned exactly the expected object. Then things got strange. The same test with 0x200C — another invisible character — returned a result even though no account named Unique{0x200C}User existed in the directory at that point, because that character had never survived the uniqueness test in the first place (Figure 8).

Look closely at that result and the odd console spacing from the earlier screenshots is gone. Verifying by SID confirmed the suspicion: the object returned was the plain UniqueUser, with no added characters at all. The Unicode character in the filter had been discarded — by PowerShell, by the DC, or somewhere in between.
If that theory held, then filtering for any object containing 0x200C should return the entire directory. Converting the Unicode value inside the console for readability, that is precisely what happened (Figure 9).

So the LDAP server’s behaviour was inconsistent: some characters were evaluated, others quietly dropped. To rule out the filter string itself as the culprit, the next stop was RFC 4515, which states:
The string representation of an LDAP search filter is a string of UTF-8-encoded Unicode characters
RFC 4515
The RFC also provides worked examples, which suggested that any Unicode character should be convertible and queryable regardless of whether it is printable. Following that specification, a helper function was written to take a Unicode hex value (for example 0x200B) and return its LDAP-filter-compatible escaped string (Figure 10).

The function was validated against 0x200B, which had already been filtered successfully in the earlier tests (Figure 11).

Then the problematic characters got the same treatment (Figure 12).

Following the RFC did not help. Running the full sweep of 385 invisible characters through LDAP produced three distinct categories:
- Filterable characters: only 106 out of 385.
- Characters treated as whitespace: invisible in the GUI, but the filter returns every object name containing a space (e.g. “Domain Admins”, “Print Operators”).
- Characters completely ignored by the DC: the filter returns all objects.
At that point the question had become personal. If the filter string could not be changed to fix this, what else could? The LDAP Extended Controls were the obvious remaining lever, and going through them, one stood out: LDAP_SERVER_SORT_OID. Its documented purpose is sort order, but Active Directory documentation notes in several places that the presence of the control also changes Unicode string comparison behaviour.
A function was written to attach LDAP_SERVER_SORT_OID and query LDAP with an arbitrary Ordering Rule OID. To test it, a scenario reported on a Microsoft forum was recreated with two users:
- Shai
- Shäi the 2nd
Note the difference between “a” (Unicode 0x0061) and “ä” (Unicode 0x00E4). Querying without the extended control (which defaults to US English) and then with the control plus a “Swedish” ordering rule produced genuinely different result sets, not merely a different sort order (Figure 13).

The same behaviour held when “ä” was converted to its UTF-8-escaped form with Convert-UnicodeToLdapUtf8 (Figure 14).

The hope was that some ordering rule would “filter the unfilterable”. A script iterated every available ordering rule against every problematic character. The conclusion was flat: no ordering rule makes the DC see any of them.
That closed the detection avenue with an unsolved problem left on the table — there are Unicode characters that Active Directory’s LDAP server ignores entirely. Which is a detection failure, and simultaneously an offensive primitive.
Changing hats
To recap the two facts that matter:
- Some Unicode characters are not parsed properly by Active Directory and therefore appear invisible.
- Some of those characters are unfilterable by LDAP, which means a filter for a “normal” value can return values that actually contain the hidden character.
Put together, that is a potential bypass of uniqueness constraints for any Unicode-based attribute. Initial testing against SamAccountName and cn showed Active Directory correctly blocking duplicate object creation even with unfilterable characters. Other attributes were not so lucky.
In 2021 Microsoft shipped a patch for CVE-2021-42282 that introduced three new uniqueness verification checks:
- User Principal Name (UPN) uniqueness
- Service Principal Name (SPN) uniqueness
- SPN alias uniqueness
Each of those values must be unique across the entire forest, and all three checks are enabled by default through the forest-wide dSHeuristics attribute. Anyone below Domain Admin who tries to set a conflicting value receives a uniqueness error.
Unfilterable characters let low-privileged users walk straight past those checks. That is the first vulnerability — named KerberLoss for its various impacts, and assigned CVE-2026-25177 by Microsoft.
KerberLoss: Starting with SPNs
Understanding the impact requires a solid grasp of Service Principal Names, which are one of the more commonly misunderstood parts of Active Directory.
What are Service Principal Names?
An SPN is how Kerberos identifies a service instance. In Active Directory terms, a service is any resource that identities access and that generally requires authentication — SMB file shares (cifs), Remote Desktop (TERMSRV), LDAP, HTTP, and so on. Those are service classes.
Services of the same class can run on different hosts, and a single host can offer several classes. An SPN therefore carries both components, in the basic form:
<service class>/<host>
Note: SPNs may also include two additional, optional components, which are beyond the scope of this paper.
Those basics are widely known. Four points deserve emphasis, because the attacks below depend on all of them:
- In the world of Active Directory and Kerberos, a service is hosted by an identity. It can be a computer account, a user account or a managed service account, but there must be an identity behind the service — this follows directly from the cryptographic model. Service tickets are encrypted with the secret belonging to the target service, meaning its identity.
- Every identity object in Active Directory carries a
servicePrincipalNameattribute holding the list of that identity’s SPNs. - When a Kerberos service ticket is requested, the Key Distribution Center (KDC) uses the SPN from the request to identify the target service — that is, the identity that holds the SPN in question.
- Kerberos tickets have a cleartext part and an encrypted part, and the SPN lives in the cleartext part. Because it is unencrypted, the SPN in a ticket can be edited, and tickets can be moved between different services of the same identity. What actually matters is which key encrypted the ticket.
What are SPN aliases?
Anyone who has managed an AD domain has seen that every computer carries a handful of default SPNs, including ones with the HOST service class (HOST/computer). If you have never had reason to look into them, they are confusing.
The Active Directory Configuration partition holds an attribute called sPNMappings, which maps SPNs to so-called SPN aliases. By default it contains a single value mapping the HOST alias to the following services:
alerter, appmgmt, cisvc, clipsrv, browser, dhcp, dnscache, replicator, eventlog, eventsystem, policyagent, oakley, dmserver, dns, mcsvc, fax, msiserver, ias, messenger, netlogon, netman, netdde, netddedsm, nmagent, plugplay, protectedstorage, rasman, rpclocator, rpc, rpcss, remoteaccess, rsvp, samss, scardsvr, scesrv, seclogon, scm, dcom, cifs, spooler, snmp, schedule, tapisrv, trksvr, trkwks, ups, time, wins, www, http, w3svc, iisadmin, msdtc
Every computer account gets a HOST class SPN when it joins the domain. When a user accesses a service that maps to HOST — cifs, http, and the rest of the list above — the KDC encrypts the service ticket with the key belonging to the account that holds the corresponding HOST SPN.
An interesting edge case
SPN alias uniqueness verification blocks the creation of conflicting mapped SPNs. If the forest contains a computer named Server holding HOST/Server, then assigning cifs/Server to a different server is refused — even though cifs/Server does not explicitly exist anywhere.
The vulnerability bypasses that check, but the detail that turns the bypass into an attack is the lookup order: the SPN lookup algorithm always searches for an explicit SPN first, and only falls back to the mapped alias when no explicit SPN is found. An attacker who can plant an explicit SPN therefore wins over the legitimate host’s implicit alias.
Demonstrating impact
Three scenarios follow, all in a simple environment with three domain-member servers:
- ServerA
- ServerB
- ServerC
The attacker operates as a non-privileged user named NotAdmin.
Scenario #1: Denial-of-service to HOST-mapped services
Assume ServerB hosts an important SMB file share. Users accessing it request service tickets for cifs/SERVERB, and because ServerB holds HOST/SERVERB by default, the DC identifies it as the account holding the relevant encryption key. If NotAdmin has WriteSPN on ServerC, adding cifs/SERVERB to ServerC is refused by SPN alias uniqueness verification (Figure 15).

Insert an invisible, unfilterable character into the string and the same operation succeeds (Figure 16).

As before, the character is not perfectly invisible in the PowerShell console — but it is invisible in dsa.msc, which is where an administrator would actually look (Figure 17).

More importantly, an LDAP query for the cifs/SERVERB SPN now returns ServerC (Figure 18).

Because explicit SPNs take precedence, every user in the domain who now tries to reach ServerB over SMB receives a ticket encrypted with ServerC’s key. ServerB cannot decrypt it, and the session dies with KRB_AP_ERR_MODIFIED. To an ordinary user, that surfaces as one of several unhelpful messages:
- The specified network name is no longer available.
- The target account name is incorrect.
- Cannot find path “path” because it does not exist.
Delete the fake SPN and access is restored immediately (Figure 19).

The net effect: WriteSPN on any computer or user account in the forest is enough to deny service to any HOST-mapped service in the forest. Figure 20 shows the flow.

Scenario #2: SPN-jacking
The second opportunity involves Kerberos constrained delegation, since classic constrained delegation is configured in terms of SPNs. The scenario here is a modified version of one from Elad Shamir’s write-up on SPN-jacking.
Note: This scenario relies on understanding Kerberos delegation attacks (i.e., “the full S4U attack”). An explanation of Kerberos delegation is beyond the scope of this paper.
Shamir’s setup: an attacker with admin access to ServerA wants admin access to ServerC. ServerA is configured for constrained delegation to cifs/ServerB, and the attacker holds WriteSPN on both ServerB and ServerC (Figure 21).

His approach to the uniqueness check was to use WriteSPN on both machines: temporarily strip HOST/SERVERB from ServerB, then add cifs/SERVERB to ServerC, run the full S4U attack through ServerA’s account to obtain a privileged service ticket to ServerC, and roll everything back afterwards.
KerberLoss plus explicit-SPN precedence removes the requirement for WriteSPN on the intermediate service entirely — a meaningful reduction in the attacker’s prerequisites. The lab was set up accordingly (Figure 22).

Exactly as in the DoS case, unfilterable characters let the attacker give ServerC the cifs/SERVERB SPN, so tickets destined for cifs/SERVERB get encrypted with ServerC’s key (Figure 23).

With that in place, the full S4U flow produces a privileged ticket to cifs/SERVERB (Figure 24).

The test that proves the point: since the SPN sits in the unencrypted part of the ticket, it can simply be rewritten to cifs/ServerC and used against ServerC. That only works if the ticket really was encrypted with ServerC’s key rather than ServerB’s — and it works (Figure 25).

Scenario #3: Authentication downgrade
Conflicting mapped SPNs cause a DoS. What happens with duplicate explicit SPNs is different, and arguably worse.
With a conflicting alias, the DC finds an SPN, issues a service ticket, and considers Kerberos to have worked. The denial of service happens later, on the resource, which cannot decrypt the ticket — hence KRB_AP_ERR_MODIFIED. With an exact duplicate of an explicit SPN, the DC finds two accounts holding the same SPN, cannot decide which key to use, and returns KDC_ERR_S_PRINCIPAL_UNKNOWN. Now the failure is signalled by the DC itself, Kerberos authentication is considered to have failed, and the client falls back to NTLM.
So WriteSPN on any computer or user account in the forest buys the attacker two things: a complete DoS of any HOST-mapped service, and the ability to force any service in the forest — HOST-mapped or not — onto NTLM only. If NTLM is disabled in the environment, the same trick becomes a denial of service instead.
From the user’s side nothing appears wrong; access continues to work (Figure 26, Figure 27).


This is the quiet one. A forced downgrade to NTLM does not break anything a user would report, and it re-opens every NTLM relay and coercion path the organisation thought it had closed by moving to Kerberos. Figure 28 illustrates the flow.

ResetNightmare: What about UPNs?
DoS and downgrade are useful, but the goal was direct privilege escalation, which meant turning to User Principal Names. Since UPN uniqueness verification is governed by the same mechanism as SPN uniqueness verification, the assumption was that it could be bypassed the same way — and it could (Figure 29).

Uniqueness verification arrived alongside a series of fixes for vulnerabilities found by Andrew Bartlett — most famously the Dollar Ticket / noPac attack (CVE-2021-42287 + CVE-2021-42278), which let any user become a domain administrator on the spot. Because that attack also hinged on DC naming confusion, the hope was that KerberLoss might revive it or lead to something similar. Either way, the next step was understanding whether and how Kerberos uses UPNs at all.
Kerberos name types
In Kerberos a principal identifier consists of a Realm and a PrincipalName, and a PrincipalName is structured as follows:
PrincipalName ::= SEQUENCE {
name-type [0] Int32,
name-string [1] SEQUENCE OF KerberosString
}
The name-string field carries the name itself, but a name alone is not sufficient to identify a principal. The name-type field states what kind of name it is — in practical terms, which attribute the DC consults first when locating the principal. RFC 4120 section 6.2 defines the possible values.
Active Directory normally identifies Kerberos clients with the NT-PRINCIPAL name type, which maps to the account’s SamAccountName. When issuing TGT requests it is also possible to use NT-ENTERPRISE, which locates accounts by their UserPrincipalName. The client name that ends up in the resulting ticket can be either the SamAccountName (NT-PRINCIPAL) or the UPN (NT-ENTERPRISE), usually governed by the Name-canonicalize flag.
Conveniently, mainstream Kerberos tooling — Rubeus and Impacket among them — already exposes the name type in TGT requests, so requesting tickets with NT-ENTERPRISE required no custom code.
The first attempt failed, though. Requesting a ticket with the duplicated UPN caused the DC to try authenticating the attacker as the privileged target, producing a pre-authentication failure (Figure 30).

It did work if DemoAdmin1‘s UPN was removed first — but that requires write permissions over the target, which makes it useless as a privilege escalation primitive (Figure 31).

The workaround is elegant and needs no unfilterable characters at all: instead of duplicating the target’s UPN, set your own UPN to the target’s SamAccountName. The strings are not identical, so uniqueness verification has no objection (Figure 32).

Requesting a ticket for DemoAdmin1 with UPNUser‘s password fails, as it should. Switch the name type to NT-ENTERPRISE, however, and out comes a ticket bearing DemoAdmin1‘s name (Figure 33).

That primitive — a ticket with an arbitrary username on it — was then thrown at every confusion idea available:
- Normal AS-REQ to TGS-REQ
- Modified Dollar Ticket attack flow
- S4U2Self abuse
- U2U Kerberos abuse
- User logon DoS, as mentioned by Andrew Bartlett
- Entra hard/soft match SyncJacking
- Cross-domain UPN precedence
Every one of them failed. Depending on the tool and the method, the result was either an error or a ticket for the correct, unprivileged user. That consistency was itself a clue worth chasing.
The CVE-2021-42287 patch
The Dollar Ticket vulnerability rested on exactly this kind of naming confusion, and Microsoft’s fix added two features to Kerberos:
- Returned TGTs always include a Privileged Attribute Certificate (PAC), even when the client explicitly asked for a ticket without one.
- The PAC in TGTs now carries a field named
PAC_REQUESTOR_SID, holding the SID of the client that requested the ticket.
PAC_REQUESTOR_SID is validated during the TGS exchange, which kills the original attack: deleting the account that requested the TGT no longer convinces the DC that the ticket belongs to the similarly named DC.
It is an excellent patch, and it is also precisely what was invalidating every UPN-confusion attempt above. The PAC always carried the attacker’s real SID, and the DC ignored the client name in the ticket entirely, treating the SID as the sole source of truth.
The natural next question — the one that turns this from a dead end into a domain takeover — is whether every Kerberos flow actually passes through a TGS exchange.
Breakthrough: (Ab)using the Kerberos Change Password protocol
By default, every Active Directory user can change their own password. One way to do it is Microsoft’s Kerberos Change Password and Set Password Protocol, which defines how password changes ride over Kerberos. The protocol is about as small as protocols get — the RFC is seven pages, with one request message and one reply message.
Microsoft’s terminology distinguishes “change password” (a user changing their own) from “set password” (an administrator setting someone else’s). The protocol listens on port 464 (kpasswd), with the request structure shown in Figure 34.

Two parts of that message matter: the KRB-PRIV message and the AP-REQ structure.
KRB-PRIV is simply a mechanism for sending encrypted data, with room for custom payloads. The protocol uses that room to carry the new password (Figure 35).

The AP-REQ structure is the interesting half. It contains a ticket plus an authenticator that proves legitimate possession of that ticket, since the authenticator is encrypted with the ticket’s session key (Figure 36).

In the usual Kerberos flow, a TGS-REQ/TGS-REP yields a service ticket and its session key, and that response is what builds the AP-REQ sent to the service.
For the Change Password protocol, the ticket inside AP-REQ must be scoped to the kadmin/changepw SPN. But that SPN belongs to the krbtgt account — and, per the earlier point about SPNs living in the cleartext part of a ticket, all that really matters is which key encrypted it. A ticket to kadmin/changepw is therefore just a TGT with its sname rewritten.
Which means changing a user’s password requires nothing more than that user’s TGT, and the flow of a Kerberos password change looks like Figure 37.

Note what is missing from that diagram. The flow goes straight from the TGT request to the AP-REQ, with no TGS-REQ in between — and the TGS-REQ is exactly where PAC_REQUESTOR_SID validation happens.
Given that a TGT with an arbitrary username was already obtainable via NT-ENTERPRISE, the question became simply whether the PAC_REQUESTOR_SID check had been implemented on this path too. The attack idea, resting on the default permission every AD user has to change their own password, runs as follows:
- The attacker controls a user named
UPNUserwith no special permissions beyond the ability to modify its own UPN value. - The attacker sets that user’s UPN to the SamAccountName of the target — for example
DemoAdmin1. No uniqueness bypass is needed:DemoAdmin1‘s real UPN isDemoAdmin1@demo.lab, so settingUPNUser‘s UPN to bareDemoAdmin1is permitted (Figure 38).

- The attacker requests a TGT for
kadmin/changepw, specifyingDemoAdmin1as the username,NT-ENTERPRISEas the name type, andUPNUser‘s password. - The DC returns a TGT that belongs to
UPNUseraccording toPAC_REQUESTOR_SIDin the PAC, but which carries the usernameDemoAdmin1with theNT_ENTERPRISEtype (Figure 39).

- Used as-is, that ticket would reset
UPNUser‘s own password. To escalate, the attacker changes or clearsUPNUser‘s UPN value, so that no account in the directory holds the UPN printed on the ticket. - Trying to use the ticket for a TGS-REQ after that change fails with
KDC_ERR_TGT_REVOKED, thanks to thePAC_REQUESTOR_SIDpatch — impersonation is properly blocked. But using the same ticket to build a password change request works. - The attacker then requests a fresh TGT for
DemoAdmin1with no name type specified. It succeeds, and the ticket’s name type isNT-PRINCIPAL, meaning it belongs to the real SamAccountName-backedDemoAdmin1account (Figure 40).

Success. The ability to write a single UPN value has become a full domain compromise.
This is ResetNightmare, assigned CVE-2026-27912. It allows complete domain takeover by an attacker holding generic Write permissions over any user or computer object in the domain, or who can create user or computer objects in the domain (MachineAccountQuota excluded). Figure 41 shows the flow end to end.

There is one additional requirement: the target’s password must be sufficiently aged. Since the default Minimum password age in Active Directory is one day, that condition is met in practice almost always.
As a bonus — credited to Andrea Pierini — the vulnerability also composes with the Shadow Credentials technique, giving a stealthier path that abuses writable computer accounts instead.
An open-source community tool, also called ResetNightmare, implements the whole flow with parameters for customising execution. It is written in PowerShell and drives Rubeus.exe together with the PowerShell ActiveDirectory module (Figure 42); it is published on GitHub.

Detecting and defending against KerberLoss and ResetNightmare
Semperis Directory Services Protector (DSP) customers can use the following new security indicators to detect several of the misconfigurations described above:
- UPN or SPN uniqueness verification is disabled
- Objects containing hidden Unicode characters
- Suspicious duplicate objects using hidden Unicode characters
- Non-privileged principal able to set a service principal name
- Non-privileged principal able to set a user principal name
DSP additionally detects anomalous SPN and UPN modifications through two indicators of compromise:
- A conflicting Service Principal Name has been added (CVE-2026-25177)
- A User Principal Name matching another account’s SAM account name has been added (CVE-2026-27912)
Without that tooling, the most practical detection route is to configure SACLs auditing Active Directory object modifications. With the SACL in place, Security log event ID 5136 (“A directory service object was modified”) on domain controllers surfaces the changes that lead to either vulnerability’s impact.
For KerberLoss, the 5136 entry shows a ServicePrincipalName being added that conflicts with an existing one (Figure 43).

For ResetNightmare, the 5136 entry shows a UserPrincipalName being added that corresponds to an existing SamAccountName (Figure 44).

The best prevention is patching every domain controller. Microsoft patched KerberLoss (CVE-2026-25177) in March 2026 and ResetNightmare (CVE-2026-27912) in April 2026.
Beyond patching, stick to least privilege and monitor for abnormal additions of non-default permissions. Tighter delegation makes both vulnerabilities materially harder to reach.
Disclosure timeline
- November 26, 2025: KerberLoss is discovered and reported to MSRC.
- December 17, 2025: ResetNightmare is discovered and reported to MSRC.
- January 9, 2026: MSRC confirms ResetNightmare works as reported.
- January 17, 2026: MSRC confirms KerberLoss works as reported.
- March 10, 2026: Microsoft patches KerberLoss (CVE-2026-25177) on Patch Tuesday as an Important Elevation of Privilege vulnerability.
- April 14, 2026: Microsoft patches ResetNightmare (CVE-2026-27912) as an Important Elevation of Privilege vulnerability.
Acknowledgements
The original author credits the following researchers, whose work inspired various parts of this research:
- Yossi Sassi (@Yossi_Sassi)
- Andrew Bartlett
- Elad Shamir (@elad_shamir)
- Charlie Clark (@exploitph)
- Will Schroeder (@harmj0y)
- Andrea Pierini (@decoder_it)
- Benjamin Delpy (@gentilkiwi)
Key Takeaways
- Of 385 “invisible” Unicode characters accepted by Active Directory, only 106 can be filtered for over LDAP. The rest are either treated as whitespace or ignored outright — a gap between what the DC stores and what the DC can search.
- That gap defeats the uniqueness verification introduced by the CVE-2021-42282 patch, because the uniqueness check is itself a search. This is KerberLoss (CVE-2026-25177).
- SPN lookup prefers an explicit SPN over a
HOSTalias, so a plantedcifs/TARGETbeats the legitimate host’s implicit mapping — turningWriteSPNon any one object into a forest-wide DoS against HOST-mapped services. - A duplicated explicit SPN produces
KDC_ERR_S_PRINCIPAL_UNKNOWNinstead, so clients silently fall back to NTLM — an authentication downgrade users never notice and NTLM-relay operators very much do. - KerberLoss also improves Elad Shamir’s SPN-jacking by removing the need for
WriteSPNon the intermediate service in a constrained-delegation chain. - ResetNightmare (CVE-2026-27912) needs no Unicode trickery at all: set your UPN to a Domain Admin’s SamAccountName, request a TGT with
NT-ENTERPRISE, clear your UPN, and drive the Kerberos Change Password protocol to reset the admin’s password. - The root cause is architectural: the change-password flow goes AS-REQ → AP-REQ with no TGS exchange, and the TGS exchange is where
PAC_REQUESTOR_SIDis validated. A patch that covers one flow does not automatically cover another.
Defensive Recommendations
- Patch every domain controller. KerberLoss was fixed in the March 2026 rollup and ResetNightmare in April 2026. A partially patched DC population leaves the attack reachable — a client only needs one vulnerable KDC to answer.
- Enable SACL auditing for directory object modifications and alert on event ID 5136 where the modified attribute is
servicePrincipalNameoruserPrincipalName. These are low-volume attributes in a healthy environment; the noise floor is manageable. - Alert specifically on a UPN whose value equals another account’s SamAccountName. That has no legitimate use and is the single clearest signature of ResetNightmare.
- Verify that UPN and SPN uniqueness verification is still enabled in the forest-wide
dSHeuristicsattribute. Some legacy migration guides recommend disabling it; if it was turned off years ago and never restored, both classes of attack become trivial regardless of patch level. - Audit who holds
WriteSPN,Write userPrincipalName, and generic Write on user and computer objects. Run BloodHound or an equivalent and treat generic Write on any object as a domain-takeover path until proven otherwise. Reduce MachineAccountQuota to 0 while you are there. - Hunt retroactively for hidden Unicode in object attributes. Because these characters cannot be filtered server-side, the sweep has to be client-side — pull
servicePrincipalName,userPrincipalName,sAMAccountNameandcnfor all objects and compare each string against its ASCII-normalised form. Anything that differs deserves a look. - Treat unexplained
KRB_AP_ERR_MODIFIEDandKDC_ERR_S_PRINCIPAL_UNKNOWNas security events, not IT noise. The user-visible symptoms — “the specified network name is no longer available”, “the target account name is incorrect” — look like ordinary breakage, which is exactly what makes the DoS variant survivable for an attacker. - Monitor Kerberos-to-NTLM fallback rates per service. A service that suddenly stops authenticating with Kerberos and has not changed is worth investigating; on hosts where NTLM has already been disabled, the same trick manifests as an outage instead.
Conclusion
Both vulnerabilities come from the same underlying idea: a domain controller does not need to have its credentials stolen if it can be persuaded to mistake one identity for another. KerberLoss achieves that by exploiting the difference between the characters Active Directory will store and the characters its LDAP server can search for, turning a documented uniqueness guarantee into an assumption that does not hold. ResetNightmare achieves it by finding the one Kerberos flow that never visits the checkpoint where a previous patch installed its identity validation. Neither requires exotic access — write permission on a single object is the entire prerequisite for full domain compromise. Patch the DCs, audit who can write SPNs and UPNs, and treat naming confusion as a first-class attack class rather than a curiosity.
More resources
- Identity Crisis: Novel Vulnerabilities Leading to Kerberos Downgrade, DoS, and Full Domain Takeover — the source research
- Semperis Identity Security Research Library
- Semperis Identity Threat Catalog
- RFC 4120 — The Kerberos Network Authentication Service (V5), section 6.2 (name types)
- RFC 4515 — LDAP: String Representation of Search Filters
Disclaimer
This content is provided for educational and informational purposes only. It is intended to promote awareness and responsible remediation of security vulnerabilities that may exist on systems you own or are authorized to test. Unauthorized use of this information for malicious purposes, exploitation, or unlawful access is strictly prohibited. Semperis does not endorse or condone any illegal activity and disclaims any liability arising from misuse of the material. Additionally, Semperis does not guarantee the accuracy or completeness of the content and assumes no liability for any damages resulting from its use.
Semperis, original article
Original text: “Identity Crisis: Novel Vulnerabilities Leading to Kerberos Downgrade, DoS, and Full Domain Takeover” by Shai Laron, Security Researcher, at Semperis.


