CVE-2026-14886High (CVSS 8.2)Fixed4 min read
A namespace check that covered memory but not storage let one Vault namespace permanently delete another's identities
Vault Enterprise's identity entity batch-delete endpoint checked the caller's namespace before removing an entity from the in-memory identity store, but not before deleting that entity's underlying storage. An authenticated caller in any namespace could destroy entities owned by another namespace, and the loss stayed invisible until the next restart. Fixed in Vault Enterprise 2.0.4, 1.21.9, 1.20.14, and 1.19.20.
- Vendor
- HashiCorp
- Product
- Vault Enterprise
- Weakness
- CWE-862
- Affected
- 2.0.0 to 2.0.3, 1.21.5 to 1.21.8, 1.20.10 to 1.20.13, 1.19.16 LTS to 1.19.19 LTS
- Fixed in
- 2.0.4, 1.21.9, 1.20.14, 1.19.20
- Advisory
- GHSA-rmq8-5gxg-mjqx
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:N/I:H/A:H
Disclosure timeline
May 19, 2026
Reported privately to HashiCorp: the identity entity batch-delete handler applies its namespace check to the in-memory delete but not to the storage delete.
Jul 6, 2026
CVE-2026-14886 reserved by HashiCorp, acting as its own CNA.
Aug 10, 2026
HCSEC-2026-27 published with named credit, alongside fixes in Vault Enterprise 2.0.4, 1.21.9, 1.20.14, and 1.19.20. IBM republished the same credit in its own bulletin; GHSA-rmq8-5gxg-mjqx mirrored the CVE record the same day.
Vault's identity system models a person or a process as an entity, a stable identifier that survives across whatever authentication methods that principal happens to use. In Vault Enterprise, namespaces sit above that: each namespace is its own administrative and access boundary, with its own policies, mounts, and entities. An entity belongs to the namespace it was created in, and nothing in one namespace is supposed to be able to reach into another.
That boundary held for the in-memory view of identity. It did not hold for the storage underneath it.
The bug
The identity/entity/batch-delete endpoint takes a list of entity IDs and deletes them. Its handler does two things per entity: remove the entity from Vault's in-memory identity database (MemDB), and remove the entity's record from the storage backend.
The handler checked the requesting namespace against each entity's namespace before the in-memory removal. It did not repeat that check before the storage removal. Entity storage is shared across namespaces and keyed only by entity ID, with no namespace component in the path, so the storage delete had nothing left to stop it. Pass the ID of an entity that lives in a different namespace and Vault would delete that entity's storage record.
The check was present. It just guarded one of the two writes.
Why it stays hidden
The interesting part is what a caller sees afterward, which is nothing.
After the storage record is gone, the entity is still in MemDB, so it still resolves, still appears in listings, and still authenticates. Vault looks healthy. The damage only surfaces when the identity store next loads from storage, on a restart or a reload, at which point the entity is simply not there. Aliases and group memberships that hung off it go with it, and there is no undo, because the authoritative copy was the thing that got deleted.
So the failure is durable, delayed, and detached from the action that caused it. An operator investigating vanished identities after a routine restart has no reason to connect it to a batch-delete call in an unrelated namespace weeks earlier. That gap between cause and symptom is what makes this worse than the raw "delete some entities" description suggests.
What it takes to reach
An authenticated caller with access to the batch-delete endpoint in some namespace. That is the whole precondition. The caller needs no access at all to the namespace that owns the target entity, no elevated privileges there, and no knowledge of its policies. What the caller does need is the target's entity ID, which is not secret but is also not enumerable from outside the owning namespace, and that is the practical friction here.
HashiCorp rated it 8.2 High: CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:N/I:H/A:H. The scope change is the namespace boundary being crossed. Confidentiality is untouched, because nothing is read; integrity and availability are both high, because identities are destroyed permanently. Vault Community Edition is unaffected, since it has no namespaces to cross.
I had argued for a higher score, on attack complexity rather than impact: I read the entity-ID requirement as low complexity, HashiCorp read it as high. Every impact metric I proposed was published unchanged. Their reading is defensible, and the one-metric gap is a fair record of where an outside reporter and the vendor's own scoring differ.
The fix
HashiCorp applied the namespace check to the storage delete as well, so both halves of the operation answer the same question before acting. Fixed in Vault Enterprise 2.0.4, 1.21.9, 1.20.14, and 1.19.20.
If you run Vault Enterprise
Upgrade to 2.0.4, 1.21.9, 1.20.14, or 1.19.20, whichever matches your release line. Then treat it as a data-integrity question rather than a credential one: nothing was disclosed, so there is nothing to rotate, but entities may already be gone from storage while still appearing live in memory. If you have namespaces with distinct owners and any of them can call batch-delete, the audit log of identity/entity/batch-delete requests is where you would find it, and a restart is what would reveal it.
The pattern worth keeping
A resource that is scoped in one layer and flat in another is where authorization quietly stops applying. Entities are namespaced in MemDB and keyed by bare ID in storage, and the check followed the model that had the namespace rather than the model that held the truth. Any time a lookup key drops a dimension the security model depends on, every write reached through that key needs its own check. Deriving the check once and reusing it across both paths, rather than writing it where the namespace happened to be in scope, is what keeps the two from drifting.