GHSA-H4HQ-RGVH-WH27
Vulnerability from github – Published: 2026-03-04 20:13 – Updated: 2026-03-04 20:13Summary
Testing confirmed that even when a Manager has manage=false for a given collection, they can still perform the following management operations as long as they have access to the collection:
PUT /api/organizations/<org_id>/collections/<col_id>succeeds (HTTP 200)PUT /api/organizations/<org_id>/collections/<col_id>/userssucceeds (HTTP 200)DELETE /api/organizations/<org_id>/collections/<col_id>succeeds (HTTP 200)
Description
- The Manager guard checks only whether the user can access the collection, not whether they have
manageprivileges. This check is directly applied to management endpoints. src/auth.rs:816 ```rust
if !Collection::can_access_collection(&headers.membership, &col_id, &conn).await { err_handler!("The current user isn't a manager for this collection") } ```
- The
can_access_collectionfunction does not evaluate themanageflag. src/db/models/collection.rs:140
```rust
pub async fn can_access_collection(member: &Membership, col_id: &CollectionId, conn: &DbConn) -> bool { member.has_status(MembershipStatus::Confirmed) && (member.has_full_access() || CollectionUser::has_access_to_collection_by_user(col_id, &member.user_uuid, conn).await || ... ```
- A separate management-permission check exists and includes
managevalidation, but it is not used during authorization for the affected endpoints. src/db/models/collection.rs:516
```rust
pub async fn is_manageable_by_user(&self, user_uuid: &UserId, conn: &DbConn) -> bool { let Some(member) = Membership::find_confirmed_by_user_and_org(user_uuid, &self.org_uuid, conn).await else { return false; }; if member.has_full_access() { return true; } ... ```
- The actual update and deletion endpoints only accept
ManagerHeadersand do not perform additionalmanagechecks. src/api/core/organizations.rs:608
async fn put_organization_collection_update(..., headers: ManagerHeaders, ...)
src/api/core/organizations.rs:890
async fn put_collection_users(..., headers: ManagerHeaders, ...)
src/api/core/organizations.rs:747
rust
async fn delete_organization_collection(..., headers: ManagerHeaders, ...)
Preconditions
- The attacker is a Manager within the target organization.
- The attacker has access to the target collection (
assigned=true). - The attacker’s permission for that collection is
manage=false. - A valid API access token has been obtained.
Steps to Reproduce
-
Confirm that the attacker’s current permissions for the target collection include
manage=false. -
As a control test, verify that update operations fail for collections the attacker cannot access.
-
Confirm that update operations succeed for the target collection where
manage=false. -
Use
PUT /collections/{col_id}/usersto setmanage=true, confirming that the attacker can escalate their own privileges. -
Verify that deletion of the collection succeeds despite the Manager lacking management rights.
Required Minimum Privileges
- Organization Manager role (Owner/Admin privileges are not required)
- Works even with
access_all=false - Only access rights to the target collection are required (
manageprivilege is not required)
Attack Scenario
A restricted Manager (intended for read/use-only access) directly invokes the API to update collection settings, elevate their own privileges to manage=true, and even delete the collection.
This allows the user to bypass operational access restrictions and effectively gain administrator-equivalent control over the collection.
Potential Impact
- Confidentiality: Expansion of access scope through unauthorized privilege escalation and configuration changes.
- Integrity: Unauthorized modification of collection settings and assignments; potential disabling of access controls.
- Availability: Deletion of collections may disrupt business operations.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.35.3"
},
"package": {
"ecosystem": "crates.io",
"name": "vaultwarden"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.35.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-27803"
],
"database_specific": {
"cwe_ids": [
"CWE-269",
"CWE-285",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-04T20:13:44Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Summary\n\nTesting confirmed that even when a Manager has `manage=false` for a given collection, they can still perform the following management operations as long as they have access to the collection:\n\n* `PUT /api/organizations/\u003corg_id\u003e/collections/\u003ccol_id\u003e` succeeds (HTTP 200)\n* `PUT /api/organizations/\u003corg_id\u003e/collections/\u003ccol_id\u003e/users` succeeds (HTTP 200)\n* `DELETE /api/organizations/\u003corg_id\u003e/collections/\u003ccol_id\u003e` succeeds (HTTP 200)\n\n\n\n## Description\n\n* The Manager guard checks only whether the user **can access the collection**, not whether they have `manage` privileges. This check is directly applied to management endpoints.\nsrc/auth.rs:816\n ```rust\n\n if !Collection::can_access_collection(\u0026headers.membership, \u0026col_id, \u0026conn).await {\n err_handler!(\"The current user isn\u0027t a manager for this collection\")\n }\n ```\n\n* The `can_access_collection` function does **not** evaluate the `manage` flag.\n src/db/models/collection.rs:140\n\n ```rust\n\n pub async fn can_access_collection(member: \u0026Membership, col_id: \u0026CollectionId, conn: \u0026DbConn) -\u003e bool {\n member.has_status(MembershipStatus::Confirmed)\n \u0026\u0026 (member.has_full_access()\n || CollectionUser::has_access_to_collection_by_user(col_id, \u0026member.user_uuid, conn).await\n || ...\n ```\n\n* A separate management-permission check exists and includes `manage` validation, but it is **not used** during authorization for the affected endpoints.\n src/db/models/collection.rs:516\n\n ```rust\n\n pub async fn is_manageable_by_user(\u0026self, user_uuid: \u0026UserId, conn: \u0026DbConn) -\u003e bool {\n let Some(member) = Membership::find_confirmed_by_user_and_org(user_uuid, \u0026self.org_uuid, conn).await else {\n return false;\n };\n if member.has_full_access() {\n return true;\n }\n ...\n ```\n\n* The actual update and deletion endpoints only accept `ManagerHeaders` and do not perform additional `manage` checks.\n src/api/core/organizations.rs:608\n\n```rust\n async fn put_organization_collection_update(..., headers: ManagerHeaders, ...)\n```\n\n src/api/core/organizations.rs:890\n\n```rust\n async fn put_collection_users(..., headers: ManagerHeaders, ...)\n```\n \n\nsrc/api/core/organizations.rs:747\n\n```rust\n async fn delete_organization_collection(..., headers: ManagerHeaders, ...)\n ```\n\n\n\n## Preconditions\n\n* The attacker is a **Manager** within the target organization.\n* The attacker has access to the target collection (`assigned=true`).\n* The attacker\u2019s permission for that collection is `manage=false`.\n* A valid API access token has been obtained.\n\n\n\n## Steps to Reproduce\n\n1. Confirm that the attacker\u2019s current permissions for the target collection include `manage=false`.\n\u003cimg width=\"2015\" height=\"636\" alt=\"image\" src=\"https://github.com/user-attachments/assets/58ddc733-e37c-4766-a980-b1ea1918ceb4\" /\u003e\n\n2. As a control test, verify that update operations fail for collections the attacker cannot access.\n\u003cimg width=\"2021\" height=\"852\" alt=\"image\" src=\"https://github.com/user-attachments/assets/d8699442-2dfc-4d73-8940-ec10f4a175f0\" /\u003e\n\n3. Confirm that update operations succeed for the target collection where `manage=false`.\n\u003cimg width=\"2013\" height=\"690\" alt=\"image\" src=\"https://github.com/user-attachments/assets/33d9845d-d18e-456c-a58c-e780911347a9\" /\u003e\n\n4. Use `PUT /collections/{col_id}/users` to set `manage=true`, confirming that the attacker can escalate their own privileges.\n\u003cimg width=\"2018\" height=\"488\" alt=\"image\" src=\"https://github.com/user-attachments/assets/da8c5246-cf2a-46c2-9a25-e99d907f852d\" /\u003e\n\n5. Verify that deletion of the collection succeeds despite the Manager lacking management rights.\n\u003cimg width=\"2018\" height=\"487\" alt=\"image\" src=\"https://github.com/user-attachments/assets/a97c8fb2-4f97-4c2a-a90b-9d95dbde84fd\" /\u003e\n\n\n\n## Required Minimum Privileges\n\n* Organization Manager role (Owner/Admin privileges are not required)\n* Works even with `access_all=false`\n* Only access rights to the target collection are required (`manage` privilege is not required)\n\n\n\n## Attack Scenario\n\nA restricted Manager (intended for read/use-only access) directly invokes the API to update collection settings, elevate their own privileges to `manage=true`, and even delete the collection.\n\nThis allows the user to bypass operational access restrictions and effectively gain administrator-equivalent control over the collection.\n\n\n\n## Potential Impact\n\n* **Confidentiality:** Expansion of access scope through unauthorized privilege escalation and configuration changes.\n* **Integrity:** Unauthorized modification of collection settings and assignments; potential disabling of access controls.\n* **Availability:** Deletion of collections may disrupt business operations.",
"id": "GHSA-h4hq-rgvh-wh27",
"modified": "2026-03-04T20:13:44Z",
"published": "2026-03-04T20:13:44Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/dani-garcia/vaultwarden/security/advisories/GHSA-h4hq-rgvh-wh27"
},
{
"type": "PACKAGE",
"url": "https://github.com/dani-garcia/vaultwarden"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L",
"type": "CVSS_V3"
}
],
"summary": "Vaultwarden\u0027s Collection Management Operations Allowed Without `manage` Verification for Manager Role"
}
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.