VYPR
High severityNVD Advisory· Published Aug 9, 2025· Updated Aug 11, 2025

OpenBao Root Namespace Operator May Elevate Token Privileges

CVE-2025-54996

Description

OpenBao exists to provide a software solution to manage, store, and distribute sensitive data including secrets, certificates, and keys. In versions 2.3.1 and below, accounts with access to highly-privileged identity entity systems in root namespaces were able to increase their scope directly to the root policy. While the identity system allowed adding arbitrary policies, which in turn could contain capability grants on arbitrary paths, the root policy was restricted to manual generation using unseal or recovery key shares. The global root policy was not accessible from child namespaces. This issue is fixed in version 2.3.2. To workaround this vulnerability, use of denied_parameters in any policy which has access to the affected identity endpoints (on identity entities) may be sufficient to prohibit this type of attack.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/openbao/openbaoGo
>= 0.1.0, < 2.3.22.3.2
github.com/openbao/openbaoGo
< 0.0.0-20250806193240-9b0b5d4f345f0.0.0-20250806193240-9b0b5d4f345f

Affected products

1

Patches

1
9b0b5d4f345f

Ensure lowercase policy in entities to forbid root policy (#1627)

https://github.com/openbao/openbaoAlexander ScheelAug 6, 2025via ghsa
5 files changed · +27 6
  • changelog/1627.txt+3 0 added
    @@ -0,0 +1,3 @@
    +```release-note:security
    +core/identity: Correctly lowercase policy names to prevent root policy assignment. HCSEC-2025-13 / CVE-2025-5999.
    +```
    
  • vault/identity_store_entities.go+3 3 modified
    @@ -355,7 +355,7 @@ func (i *IdentityStore) handleEntityUpdateCommon() framework.OperationFunc {
     		// Update the policies if supplied
     		entityPoliciesRaw, ok := d.GetOk("policies")
     		if ok {
    -			entity.Policies = strutil.RemoveDuplicates(entityPoliciesRaw.([]string), false)
    +			entity.Policies = strutil.RemoveDuplicates(entityPoliciesRaw.([]string), true /* lowercase */)
     		}
     
     		if strutil.StrListContains(entity.Policies, "root") {
    @@ -470,7 +470,7 @@ func (i *IdentityStore) handleEntityReadCommon(ctx context.Context, entity *iden
     	respData["name"] = entity.Name
     	respData["metadata"] = entity.Metadata
     	respData["merged_entity_ids"] = entity.MergedEntityIDs
    -	respData["policies"] = strutil.RemoveDuplicates(entity.Policies, false)
    +	respData["policies"] = strutil.RemoveDuplicates(entity.Policies, true /* lowercase */)
     	respData["disabled"] = entity.Disabled
     	respData["namespace_id"] = entity.NamespaceID
     
    @@ -1061,7 +1061,7 @@ func (i *IdentityStore) mergeEntity(ctx context.Context, txn *memdb.Txn, toEntit
     
     		// If told to, merge policies
     		if mergePolicies {
    -			toEntity.Policies = strutil.RemoveDuplicates(strutil.MergeSlices(toEntity.Policies, fromEntity.Policies), false)
    +			toEntity.Policies = strutil.RemoveDuplicates(strutil.MergeSlices(toEntity.Policies, fromEntity.Policies), true /* lowercase */)
     		}
     
     		// If the entity from which we are merging from was already a merged
    
  • vault/identity_store_entities_test.go+19 1 modified
    @@ -938,7 +938,7 @@ func TestIdentityStore_EntityCRUD(t *testing.T) {
     
     	if resp.Data["id"] != id ||
     		resp.Data["name"] != registerData["name"] ||
    -		!reflect.DeepEqual(resp.Data["policies"], strutil.RemoveDuplicates(registerData["policies"].([]string), false)) {
    +		!reflect.DeepEqual(resp.Data["policies"], strutil.RemoveDuplicates(registerData["policies"].([]string), true /* lowercase */)) {
     		t.Fatal("bad: entity response")
     	}
     
    @@ -970,6 +970,24 @@ func TestIdentityStore_EntityCRUD(t *testing.T) {
     		t.Fatalf("bad: entity response after update; resp: %#v\n updateData: %#v\n", resp.Data, updateData)
     	}
     
    +	// For HCSEC-2025-13 / CVE-2025-5999, validate that we cannot set root
    +	// policies with other casing.
    +	for _, name := range []string{"rooT", "Root", "rOoT", "root", "root ", " root"} {
    +		updateReq.Data = map[string]interface{}{
    +			"policies": []string{name},
    +		}
    +		resp, err = is.HandleRequest(ctx, updateReq)
    +		if err == nil && (resp == nil || !resp.IsError()) {
    +			t.Fatalf("[policy: %v] err:%v resp:%#v", name, err, resp)
    +		}
    +
    +		resp, err = is.HandleRequest(ctx, readReq)
    +		if err != nil || (resp != nil && resp.IsError()) {
    +			t.Fatalf("err:%v resp:%#v", err, resp)
    +		}
    +		require.NotContains(t, resp.Data["policies"].([]string), "root")
    +	}
    +
     	deleteReq := &logical.Request{
     		Path:      "entity/id/" + id,
     		Operation: logical.DeleteOperation,
    
  • vault/identity_store_util.go+1 1 modified
    @@ -1392,7 +1392,7 @@ func (i *IdentityStore) sanitizeAndUpsertGroup(ctx context.Context, group *ident
     
     	// Remove duplicate policies
     	if group.Policies != nil {
    -		group.Policies = strutil.RemoveDuplicates(group.Policies, false)
    +		group.Policies = strutil.RemoveDuplicates(group.Policies, true /* lowercase */)
     	}
     
     	txn := i.db(ctx).Txn(true)
    
  • vault/request_handling.go+1 1 modified
    @@ -203,7 +203,7 @@ func (c *Core) filterGroupPoliciesByNS(ctx context.Context, tokenNS *namespace.N
     		if err != nil && err != ErrNoApplicablePolicies {
     			return nil, err
     		}
    -		filteredPolicies = strutil.RemoveDuplicates(filteredPolicies, false)
    +		filteredPolicies = strutil.RemoveDuplicates(filteredPolicies, true /* lowercase */)
     		if len(filteredPolicies) != 0 {
     			policies[nsID] = append(policies[nsID], filteredPolicies...)
     		}
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

8

News mentions

0

No linked articles in our index yet.