VYPR
High severity8.1NVD Advisory· Published May 11, 2026· Updated May 16, 2026

CVE-2026-43640

CVE-2026-43640

Description

Bitwarden Server prior to v2026.4.1 does not require master-password re-authentication when retrieving or rotating an organization's SCIM API key, allowing an authenticated user with SCIM management privileges to obtain the key using only a valid session.

Affected products

1

Patches

1
eb251d9bf807

Removing not scim check from api-key and rotate-api-key (#7403)

https://github.com/bitwarden/serverJared McCannonApr 8, 2026via nvd-ref
2 files changed · +120 15
  • src/Api/AdminConsole/Controllers/OrganizationsController.cs+9 15 modified
    @@ -394,17 +394,14 @@ public async Task<ApiKeyResponseModel> ApiKey(string id, [FromBody] Organization
                 throw new UnauthorizedAccessException();
             }
     
    -        if (model.Type != OrganizationApiKeyType.Scim
    -            && !await _userService.VerifySecretAsync(user, model.Secret))
    +        if (!await _userService.VerifySecretAsync(user, model.Secret))
             {
                 await Task.Delay(2000);
                 throw new BadRequestException("MasterPasswordHash", "Invalid password.");
             }
    -        else
    -        {
    -            var response = new ApiKeyResponseModel(organizationApiKey);
    -            return response;
    -        }
    +
    +        var response = new ApiKeyResponseModel(organizationApiKey);
    +        return response;
         }
     
         [HttpGet("{id}/api-key-information/{type?}")]
    @@ -447,18 +444,15 @@ public async Task<ApiKeyResponseModel> RotateApiKey(string id, [FromBody] Organi
                 throw new UnauthorizedAccessException();
             }
     
    -        if (model.Type != OrganizationApiKeyType.Scim
    -            && !await _userService.VerifySecretAsync(user, model.Secret))
    +        if (!await _userService.VerifySecretAsync(user, model.Secret))
             {
                 await Task.Delay(2000);
                 throw new BadRequestException("MasterPasswordHash", "Invalid password.");
             }
    -        else
    -        {
    -            await _rotateOrganizationApiKeyCommand.RotateApiKeyAsync(organizationApiKey);
    -            var response = new ApiKeyResponseModel(organizationApiKey);
    -            return response;
    -        }
    +
    +        await _rotateOrganizationApiKeyCommand.RotateApiKeyAsync(organizationApiKey);
    +        var response = new ApiKeyResponseModel(organizationApiKey);
    +        return response;
         }
     
         private async Task<bool> HasApiKeyAccessAsync(Guid orgId, OrganizationApiKeyType? type)
    
  • test/Api.Test/AdminConsole/Controllers/OrganizationsControllerTests.cs+111 0 modified
    @@ -1,12 +1,14 @@
     using System.Security.Claims;
     using Bit.Api.AdminConsole.Controllers;
    +using Bit.Api.AdminConsole.Models.Request.Organizations;
     using Bit.Api.Auth.Models.Request.Accounts;
     using Bit.Api.Models.Request.Organizations;
     using Bit.Core.AdminConsole.Entities;
     using Bit.Core.AdminConsole.Enums;
     using Bit.Core.AdminConsole.Enums.Provider;
     using Bit.Core.AdminConsole.Models.Business;
     using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
    +using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys.Interfaces;
     using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces;
     using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
     using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
    @@ -228,4 +230,113 @@ await sutProvider.GetDependency<IOrganizationService>()
                         s.LimitItemDeletion == model.LimitItemDeletion &&
                         s.AllowAdminAccessToAllCollectionItems == model.AllowAdminAccessToAllCollectionItems));
         }
    +
    +    [Theory, BitAutoData]
    +    public async Task ApiKey_ScimType_InvalidSecret_ThrowsBadRequest(
    +        SutProvider<OrganizationsController> sutProvider,
    +        Organization organization,
    +        OrganizationApiKey organizationApiKey,
    +        User user)
    +    {
    +        organization.PlanType = PlanType.EnterpriseAnnually;
    +        var model = new OrganizationApiKeyRequestModel
    +        {
    +            Type = OrganizationApiKeyType.Scim,
    +            MasterPasswordHash = "invalid-hash"
    +        };
    +
    +        sutProvider.GetDependency<ICurrentContext>().ManageScim(organization.Id).Returns(true);
    +        sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
    +        sutProvider.GetDependency<IGetOrganizationApiKeyQuery>()
    +            .GetOrganizationApiKeyAsync(organization.Id, OrganizationApiKeyType.Scim)
    +            .Returns(organizationApiKey);
    +
    +        var userService = sutProvider.GetDependency<IUserService>();
    +        userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
    +        userService.VerifySecretAsync(user, model.Secret).Returns(false);
    +
    +        await Assert.ThrowsAsync<BadRequestException>(
    +            () => sutProvider.Sut.ApiKey(organization.Id.ToString(), model));
    +    }
    +
    +    [Theory, BitAutoData]
    +    public async Task ApiKey_ScimType_ValidSecret_ReturnsApiKey(
    +        SutProvider<OrganizationsController> sutProvider,
    +        Organization organization,
    +        OrganizationApiKey organizationApiKey,
    +        User user)
    +    {
    +        organization.PlanType = PlanType.EnterpriseAnnually;
    +        var model = new OrganizationApiKeyRequestModel
    +        {
    +            Type = OrganizationApiKeyType.Scim,
    +            MasterPasswordHash = "valid-hash"
    +        };
    +
    +        sutProvider.GetDependency<ICurrentContext>().ManageScim(organization.Id).Returns(true);
    +        sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
    +        sutProvider.GetDependency<IGetOrganizationApiKeyQuery>()
    +            .GetOrganizationApiKeyAsync(organization.Id, OrganizationApiKeyType.Scim)
    +            .Returns(organizationApiKey);
    +        var userService = sutProvider.GetDependency<IUserService>();
    +        userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
    +        userService.VerifySecretAsync(user, model.Secret).Returns(true);
    +
    +        var result = await sutProvider.Sut.ApiKey(organization.Id.ToString(), model);
    +
    +        Assert.Equal(organizationApiKey.ApiKey, result.ApiKey);
    +    }
    +
    +    [Theory, BitAutoData]
    +    public async Task RotateApiKey_ScimType_InvalidSecret_ThrowsBadRequest(
    +        SutProvider<OrganizationsController> sutProvider,
    +        Organization organization,
    +        OrganizationApiKey organizationApiKey,
    +        User user)
    +    {
    +        var model = new OrganizationApiKeyRequestModel
    +        {
    +            Type = OrganizationApiKeyType.Scim,
    +            MasterPasswordHash = "invalid-hash"
    +        };
    +
    +        sutProvider.GetDependency<ICurrentContext>().ManageScim(organization.Id).Returns(true);
    +        sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
    +        sutProvider.GetDependency<IGetOrganizationApiKeyQuery>()
    +            .GetOrganizationApiKeyAsync(organization.Id, OrganizationApiKeyType.Scim)
    +            .Returns(organizationApiKey);
    +        var userService = sutProvider.GetDependency<IUserService>();
    +        userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
    +        userService.VerifySecretAsync(user, model.Secret).Returns(false);
    +
    +        await Assert.ThrowsAsync<BadRequestException>(
    +            () => sutProvider.Sut.RotateApiKey(organization.Id.ToString(), model));
    +    }
    +
    +    [Theory, BitAutoData]
    +    public async Task RotateApiKey_ScimType_ValidSecret_ReturnsApiKey(
    +        SutProvider<OrganizationsController> sutProvider,
    +        Organization organization,
    +        OrganizationApiKey organizationApiKey,
    +        User user)
    +    {
    +        var model = new OrganizationApiKeyRequestModel
    +        {
    +            Type = OrganizationApiKeyType.Scim,
    +            MasterPasswordHash = "valid-hash"
    +        };
    +
    +        sutProvider.GetDependency<ICurrentContext>().ManageScim(organization.Id).Returns(true);
    +        sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
    +        sutProvider.GetDependency<IGetOrganizationApiKeyQuery>()
    +            .GetOrganizationApiKeyAsync(organization.Id, OrganizationApiKeyType.Scim)
    +            .Returns(organizationApiKey);
    +        var userService = sutProvider.GetDependency<IUserService>();
    +        userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
    +        userService.VerifySecretAsync(user, model.Secret).Returns(true);
    +
    +        var result = await sutProvider.Sut.RotateApiKey(organization.Id.ToString(), model);
    +
    +        Assert.Equal(organizationApiKey.ApiKey, result.ApiKey);
    +    }
     }
    

Vulnerability mechanics

AI mechanics synthesis has not run for this CVE yet.

References

5

News mentions

0

No linked articles in our index yet.