bitwarden/server · error · UnauthorizedAccessException

Unauthorized.

Error message

Unauthorized.

What it means

Thrown at SecretsTrashController.cs:51 inside ListByOrganizationAsync. After the SM-access check passed, the second guard requires OrganizationAdmin; if false the controller throws UnauthorizedAccessException, which ExceptionHandlerEndpointFilter maps to HTTP 401 with body "Unauthorized.". Trash listing is admin-only: an SM member who is not an org admin cannot enumerate trashed secrets.

Source

Thrown at src/Api/SecretsManager/Controllers/SecretsTrashController.cs:51

        _currentContext = currentContext;
        _secretRepository = secretRepository;
        _emptyTrashCommand = emptyTrashCommand;
        _restoreTrashCommand = restoreTrashCommand;
        _userService = userService;
        _eventService = eventService;
    }

    [HttpGet("secrets/{organizationId}/trash")]
    public async Task<SecretWithProjectsListResponseModel> ListByOrganizationAsync(Guid organizationId)
    {
        if (!_currentContext.AccessSecretsManager(organizationId))
        {
            throw new NotFoundException();
        }

        if (!await _currentContext.OrganizationAdmin(organizationId))
        {
            throw new UnauthorizedAccessException();
        }

        var secrets = await _secretRepository.GetManyDetailsByOrganizationIdInTrashAsync(organizationId);
        return new SecretWithProjectsListResponseModel(secrets);
    }

    [HttpPost("secrets/{organizationId}/trash/empty")]
    public async Task EmptyTrashAsync(Guid organizationId, [FromBody] List<Guid> ids)
    {
        if (!_currentContext.AccessSecretsManager(organizationId))
        {
            throw new NotFoundException();
        }

        if (!await _currentContext.OrganizationAdmin(organizationId))
        {
            throw new UnauthorizedAccessException();
        }

View on GitHub (pinned to e93b962371)

Solutions

  1. Have an organization admin perform the trash listing.
  2. Promote the user to an admin role in the organization if trash access is required.
  3. Use an admin-scoped API token for automated trash queries.

Example fix

// before: SM user (non-admin) lists trash
await smUserClient.GetAsync($"/secrets/{orgId}/trash"); // 401

// after: admin identity lists trash
var adminClient = ClientFor(orgAdminCredential);
await adminClient.GetAsync($"/secrets/{orgId}/trash");
Defensive patterns

Strategy: validation

Validate before calling

if (!await IsOrganizationAdminAsync(orgId))
    throw new UnauthorizedAccessException("Trash listing requires org admin");
await adminClient.GetAsync($"/secrets/{orgId}/trash");

Try / catch

try { await client.GetAsync($"/secrets/{orgId}/trash"); }
catch (ApiException ex) when (ex.StatusCode == HttpStatusCode.Unauthorized) { Log.Warn("Admin role required for trash"); }

Prevention

When it happens

Trigger: GET /secrets/{orgId}/trash by a user who has Secrets Manager access but is not an organization admin (e.g. a custom role or standard SM user).

Common situations: Non-admin SM user opening the trash view; service account or limited role attempting trash enumeration; admin rights removed after SM seat granted.

Understand the failure class

Related errors


AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13). Data as JSON: /api/errors/c060f383802830a0. Report an issue: GitHub.