Inconsistent permissions shown on clients for members with multiple groups #5837

Closed
opened 2026-03-07 20:40:00 -06:00 by GiteaMirror · 9 comments
Owner

Originally created by @MartinK07 on GitHub (Feb 13, 2025).

Originally assigned to: @BlackDex on GitHub.

Vaultwarden Support String

Your environment (Generated via diagnostics page)

  • Vaultwarden version: v1.33.2
  • Web-vault version: v2025.1.1
  • OS/Arch: linux/x86_64
  • Running within a container: true (Base: Debian)
  • Database type: SQLite
  • Database version: 3.48.0
  • Environment settings overridden!: false
  • Uses a reverse proxy: true
  • IP Header check: true (X-Real-IP)
  • Internet access: true
  • Internet access via a proxy: false
  • DNS Check: true
  • Browser/Server Time Check: true
  • Server/NTP Time Check: true
  • Domain Configuration Check: true
  • HTTPS Check: true
  • Websocket Check: true
  • HTTP Response Checks: true

Config & Details (Generated via diagnostics page)

Show Config & Details

Config:

{
  "_duo_akey": null,
  "_enable_duo": true,
  "_enable_email_2fa": false,
  "_enable_smtp": true,
  "_enable_yubico": true,
  "_icon_service_csp": "",
  "_icon_service_url": "",
  "_ip_header_enabled": true,
  "_max_note_size": 10000,
  "_smtp_img_src": "***:",
  "admin_ratelimit_max_burst": 3,
  "admin_ratelimit_seconds": 300,
  "admin_session_lifetime": 20,
  "admin_token": "***",
  "allowed_connect_src": "",
  "allowed_iframe_ancestors": "",
  "attachments_folder": "data/attachments",
  "auth_request_purge_schedule": "30 * * * * *",
  "authenticator_disable_time_drift": false,
  "data_folder": "data",
  "database_conn_init": "",
  "database_max_conns": 10,
  "database_timeout": 30,
  "database_url": "***************",
  "db_connection_retries": 15,
  "disable_2fa_remember": false,
  "disable_admin_token": false,
  "disable_icon_download": false,
  "domain": "*****://****************",
  "domain_origin": "*****://****************",
  "domain_path": "",
  "domain_set": true,
  "duo_context_purge_schedule": "30 * * * * *",
  "duo_host": null,
  "duo_ikey": null,
  "duo_skey": null,
  "duo_use_iframe": false,
  "email_2fa_auto_fallback": false,
  "email_2fa_enforce_on_verified_invite": false,
  "email_attempts_limit": 3,
  "email_change_allowed": true,
  "email_expiration_time": 600,
  "email_token_size": 6,
  "emergency_access_allowed": true,
  "emergency_notification_reminder_schedule": "0 3 * * * *",
  "emergency_request_timeout_schedule": "0 7 * * * *",
  "enable_db_wal": true,
  "enable_websocket": true,
  "enforce_single_org_with_reset_pw_policy": false,
  "event_cleanup_schedule": "0 10 0 * * *",
  "events_days_retain": null,
  "experimental_client_feature_flags": "fido2-vault-credentials",
  "extended_logging": true,
  "helo_name": null,
  "hibp_api_key": null,
  "http_request_block_non_global_ips": true,
  "http_request_block_regex": null,
  "icon_blacklist_non_global_ips": true,
  "icon_blacklist_regex": null,
  "icon_cache_folder": "data/icon_cache",
  "icon_cache_negttl": 259200,
  "icon_cache_ttl": 2592000,
  "icon_download_timeout": 10,
  "icon_redirect_code": 302,
  "icon_service": "internal",
  "incomplete_2fa_schedule": "30 * * * * *",
  "incomplete_2fa_time_limit": 3,
  "increase_note_size_limit": false,
  "invitation_expiration_hours": 120,
  "invitation_org_name": "Vaultwarden",
  "invitations_allowed": true,
  "ip_header": "X-Real-IP",
  "job_poll_interval_ms": 30000,
  "log_file": null,
  "log_level": "info",
  "log_timestamp_format": "%Y-%m-%d %H:%M:%S.%3f",
  "login_ratelimit_max_burst": 10,
  "login_ratelimit_seconds": 60,
  "org_attachment_limit": null,
  "org_creation_users": "",
  "org_events_enabled": false,
  "org_groups_enabled": true,
  "password_hints_allowed": true,
  "password_iterations": 600000,
  "push_enabled": false,
  "push_identity_uri": "https://identity.bitwarden.com",
  "push_installation_id": "***",
  "push_installation_key": "***",
  "push_relay_uri": "https://push.bitwarden.com",
  "reload_templates": false,
  "require_device_email": false,
  "rsa_key_filename": "data/rsa_key",
  "send_purge_schedule": "0 5 * * * *",
  "sendmail_command": null,
  "sends_allowed": true,
  "sends_folder": "data/sends",
  "show_password_hint": false,
  "signups_allowed": true,
  "signups_domains_whitelist": "",
  "signups_verify": false,
  "signups_verify_resend_limit": 6,
  "signups_verify_resend_time": 3600,
  "smtp_accept_invalid_certs": false,
  "smtp_accept_invalid_hostnames": false,
  "smtp_auth_mechanism": null,
  "smtp_debug": false,
  "smtp_embed_images": true,
  "smtp_explicit_tls": null,
  "smtp_from": "",
  "smtp_from_name": "Vaultwarden",
  "smtp_host": null,
  "smtp_password": null,
  "smtp_port": 587,
  "smtp_security": "starttls",
  "smtp_ssl": null,
  "smtp_timeout": 15,
  "smtp_username": null,
  "templates_folder": "data/templates",
  "tmp_folder": "data/tmp",
  "trash_auto_delete_days": null,
  "trash_purge_schedule": "0 5 0 * * *",
  "use_sendmail": false,
  "use_syslog": false,
  "user_attachment_limit": null,
  "user_send_limit": null,
  "web_vault_enabled": true,
  "web_vault_folder": "web-vault/",
  "yubico_client_id": null,
  "yubico_secret_key": null,
  "yubico_server": null
}

Vaultwarden Build Version

v1.33.2

Deployment method

Official Container Image

Custom deployment method

No response

Reverse Proxy

Traefik 2.11.10

Host/Server Operating System

Linux

Operating System Version

Kubernetes

Clients

Web Vault

Client Version

Web-vault: v2025.1.1, Desktop 2025.2.0, Browser 2024.12.4 (Firefox)

Steps To Reproduce

  1. Create UserA, GroupA, GroupB, CollectionA and ItemA assigned to CollectionA.
  2. Give GroupA readonly permissions for CollectionA.
  3. Give GroupB readwrite permissions for CollectionA.
  4. Add UserA to both groups. (A Member with the user role)
  5. UserA has readwrite access to ItemA.
  6. In the Admin Console, open the edit dialog for GroupA and click save without changing anything.
  7. After a client reload, clients for UserA now only show readonly access to Items in CollectionA. (grayed out fields, etc)

Expected Result

User permissions are consistent regardless which member group was updated/changed most recent.

Actual Result

The most recent updated member group determines the visible permission on the clients.

Logs


Screenshots or Videos

No response

Additional Context

Although the permissions are shown as readonly, clients like the bw cli tool have readwrite access to items in CollectionA.

Also, opening ItemA in edit mode on the browser extension (no fields are modifiable) and clicking save (without making changes), ItemA suddenly appears are readwrite able in the UI of all clients (Webvault, Desktop, browser extension).

Is this a bug in Vaultwarden or on all the Bitwarden clients?

Originally created by @MartinK07 on GitHub (Feb 13, 2025). Originally assigned to: @BlackDex on GitHub. ### Vaultwarden Support String ### Your environment (Generated via diagnostics page) * Vaultwarden version: v1.33.2 * Web-vault version: v2025.1.1 * OS/Arch: linux/x86_64 * Running within a container: true (Base: Debian) * Database type: SQLite * Database version: 3.48.0 * Environment settings overridden!: false * Uses a reverse proxy: true * IP Header check: true (X-Real-IP) * Internet access: true * Internet access via a proxy: false * DNS Check: true * Browser/Server Time Check: true * Server/NTP Time Check: true * Domain Configuration Check: true * HTTPS Check: true * Websocket Check: true * HTTP Response Checks: true ### Config & Details (Generated via diagnostics page) <details><summary>Show Config & Details</summary> **Config:** ```json { "_duo_akey": null, "_enable_duo": true, "_enable_email_2fa": false, "_enable_smtp": true, "_enable_yubico": true, "_icon_service_csp": "", "_icon_service_url": "", "_ip_header_enabled": true, "_max_note_size": 10000, "_smtp_img_src": "***:", "admin_ratelimit_max_burst": 3, "admin_ratelimit_seconds": 300, "admin_session_lifetime": 20, "admin_token": "***", "allowed_connect_src": "", "allowed_iframe_ancestors": "", "attachments_folder": "data/attachments", "auth_request_purge_schedule": "30 * * * * *", "authenticator_disable_time_drift": false, "data_folder": "data", "database_conn_init": "", "database_max_conns": 10, "database_timeout": 30, "database_url": "***************", "db_connection_retries": 15, "disable_2fa_remember": false, "disable_admin_token": false, "disable_icon_download": false, "domain": "*****://****************", "domain_origin": "*****://****************", "domain_path": "", "domain_set": true, "duo_context_purge_schedule": "30 * * * * *", "duo_host": null, "duo_ikey": null, "duo_skey": null, "duo_use_iframe": false, "email_2fa_auto_fallback": false, "email_2fa_enforce_on_verified_invite": false, "email_attempts_limit": 3, "email_change_allowed": true, "email_expiration_time": 600, "email_token_size": 6, "emergency_access_allowed": true, "emergency_notification_reminder_schedule": "0 3 * * * *", "emergency_request_timeout_schedule": "0 7 * * * *", "enable_db_wal": true, "enable_websocket": true, "enforce_single_org_with_reset_pw_policy": false, "event_cleanup_schedule": "0 10 0 * * *", "events_days_retain": null, "experimental_client_feature_flags": "fido2-vault-credentials", "extended_logging": true, "helo_name": null, "hibp_api_key": null, "http_request_block_non_global_ips": true, "http_request_block_regex": null, "icon_blacklist_non_global_ips": true, "icon_blacklist_regex": null, "icon_cache_folder": "data/icon_cache", "icon_cache_negttl": 259200, "icon_cache_ttl": 2592000, "icon_download_timeout": 10, "icon_redirect_code": 302, "icon_service": "internal", "incomplete_2fa_schedule": "30 * * * * *", "incomplete_2fa_time_limit": 3, "increase_note_size_limit": false, "invitation_expiration_hours": 120, "invitation_org_name": "Vaultwarden", "invitations_allowed": true, "ip_header": "X-Real-IP", "job_poll_interval_ms": 30000, "log_file": null, "log_level": "info", "log_timestamp_format": "%Y-%m-%d %H:%M:%S.%3f", "login_ratelimit_max_burst": 10, "login_ratelimit_seconds": 60, "org_attachment_limit": null, "org_creation_users": "", "org_events_enabled": false, "org_groups_enabled": true, "password_hints_allowed": true, "password_iterations": 600000, "push_enabled": false, "push_identity_uri": "https://identity.bitwarden.com", "push_installation_id": "***", "push_installation_key": "***", "push_relay_uri": "https://push.bitwarden.com", "reload_templates": false, "require_device_email": false, "rsa_key_filename": "data/rsa_key", "send_purge_schedule": "0 5 * * * *", "sendmail_command": null, "sends_allowed": true, "sends_folder": "data/sends", "show_password_hint": false, "signups_allowed": true, "signups_domains_whitelist": "", "signups_verify": false, "signups_verify_resend_limit": 6, "signups_verify_resend_time": 3600, "smtp_accept_invalid_certs": false, "smtp_accept_invalid_hostnames": false, "smtp_auth_mechanism": null, "smtp_debug": false, "smtp_embed_images": true, "smtp_explicit_tls": null, "smtp_from": "", "smtp_from_name": "Vaultwarden", "smtp_host": null, "smtp_password": null, "smtp_port": 587, "smtp_security": "starttls", "smtp_ssl": null, "smtp_timeout": 15, "smtp_username": null, "templates_folder": "data/templates", "tmp_folder": "data/tmp", "trash_auto_delete_days": null, "trash_purge_schedule": "0 5 0 * * *", "use_sendmail": false, "use_syslog": false, "user_attachment_limit": null, "user_send_limit": null, "web_vault_enabled": true, "web_vault_folder": "web-vault/", "yubico_client_id": null, "yubico_secret_key": null, "yubico_server": null } ``` </details> ### Vaultwarden Build Version v1.33.2 ### Deployment method Official Container Image ### Custom deployment method _No response_ ### Reverse Proxy Traefik 2.11.10 ### Host/Server Operating System Linux ### Operating System Version Kubernetes ### Clients Web Vault ### Client Version Web-vault: v2025.1.1, Desktop 2025.2.0, Browser 2024.12.4 (Firefox) ### Steps To Reproduce 1. Create UserA, GroupA, GroupB, CollectionA and ItemA assigned to CollectionA. 2. Give GroupA readonly permissions for CollectionA. 3. Give GroupB readwrite permissions for CollectionA. 4. Add UserA to both groups. (A Member with the user role) 5. UserA has readwrite access to ItemA. 6. In the Admin Console, open the edit dialog for GroupA and click save without changing anything. 7. After a client reload, clients for UserA now only show readonly access to Items in CollectionA. (grayed out fields, etc) ### Expected Result User permissions are consistent regardless which member group was updated/changed most recent. ### Actual Result The most recent updated member group determines the visible permission on the clients. ### Logs ```text ``` ### Screenshots or Videos _No response_ ### Additional Context Although the permissions are shown as readonly, clients like the bw cli tool have readwrite access to items in CollectionA. Also, opening ItemA in edit mode on the browser extension (no fields are modifiable) and clicking save (without making changes), ItemA suddenly appears are readwrite able in the UI of all clients (Webvault, Desktop, browser extension). Is this a bug in Vaultwarden or on all the Bitwarden clients?
GiteaMirror added the bug label 2026-03-07 20:40:00 -06:00
Author
Owner

@BlackDex commented on GitHub (May 19, 2025):

This seems to be fixed either via the web-vault or an other PR already.
It might also be fixed via my #5798 PR which is not yet merged, but i tested this using that code-base.

@BlackDex commented on GitHub (May 19, 2025): This seems to be fixed either via the web-vault or an other PR already. It might also be fixed via my #5798 PR which is not yet merged, but i tested this using that code-base.
Author
Owner

@MartinK07 commented on GitHub (Jun 2, 2025):

I just tested with the version 1.34.1, sadly the problem is still present.

@MartinK07 commented on GitHub (Jun 2, 2025): I just tested with the version 1.34.1, sadly the problem is still present.
Author
Owner

@BlackDex commented on GitHub (Jun 2, 2025):

Have you repeated all the steps? Or did you used the current configured settings?
Because it might be that the stored rights using an older version were incorrect.
Back then i did all your steps and it worked not having your issue.

@BlackDex commented on GitHub (Jun 2, 2025): Have you repeated all the steps? Or did you used the current configured settings? Because it might be that the stored rights using an older version were incorrect. Back then i did all your steps and it worked not having your issue.
Author
Owner

@MartinK07 commented on GitHub (Jun 2, 2025):

I tested with my current environment that i upgraded from v1.33.2, but i created new groups for testing.
The problem that the edit permissions vanish in the webvault, if I resave the group that has the view only permissions is still present.

edit: I also just tested with a new environment and the problem as described in the issue is still reproducible there too.

@MartinK07 commented on GitHub (Jun 2, 2025): I tested with my current environment that i upgraded from v1.33.2, but i created new groups for testing. The problem that the edit permissions vanish in the webvault, if I resave the group that has the view only permissions is still present. edit: I also just tested with a new environment and the problem as described in the issue is still reproducible there too.
Author
Owner

@BlackDex commented on GitHub (Jun 2, 2025):

Ok, i tested it again, and i can now reproduce it for some reason.

@BlackDex commented on GitHub (Jun 2, 2025): Ok, i tested it again, and i can now reproduce it for some reason.
Author
Owner

@stefan0xC commented on GitHub (Jul 9, 2025):

Looking into the proposed fix #6017 the issue from what I can tell is that we wrongly assumed that we will only store one CollectionGroup for any given collection in the respective HashMap e718afb441/src/api/core/ciphers.rs (L1926-L1931) even though you can be member of multiple groups.

So the potential issue arises when actually calculating the permissions for each collection e718afb441/src/api/core/ciphers.rs (L140) because we only check the first result of each HashMap which is fine for directly assigned collections but not for groups 3b48e6e903/src/db/models/collection.rs (L102-L107)
Also by checking both HashMaps sequentially and separately from each other the directly assigned permissions will always precede a group permission (which might be okay if it is intentional - but if it's not we should probably rewrite the way we calculate it).

@BlackDex To reliably reproduce the issue I would create two collections (e.g. a and b) and two groups (read a, manage b and manage a, read b each with the corresponding permissions). If you now add a User to both groups they will have the issue in one of those collections regardless of which group is used for calculating the permissions.

@stefan0xC commented on GitHub (Jul 9, 2025): Looking into the proposed fix #6017 the issue from what I can tell is that we wrongly assumed that we will only store one `CollectionGroup` for any given collection in the respective `HashMap` https://github.com/dani-garcia/vaultwarden/blob/e718afb441f6ddd0ac6b2fc5891056729f1790d2/src/api/core/ciphers.rs#L1926-L1931 even though you can be member of multiple groups. So the potential issue arises when actually calculating the permissions for each collection https://github.com/dani-garcia/vaultwarden/blob/e718afb441f6ddd0ac6b2fc5891056729f1790d2/src/api/core/ciphers.rs#L140 because we only check the first result of each `HashMap` which is fine for directly assigned collections but not for groups https://github.com/dani-garcia/vaultwarden/blob/3b48e6e90386bcee3e8a2b99ec2472cba979adf1/src/db/models/collection.rs#L102-L107 Also by checking both HashMaps sequentially and separately from each other the directly assigned permissions will always precede a group permission (which might be okay if it is intentional - but if it's not we should probably rewrite the way we calculate it). @BlackDex To reliably reproduce the issue I would create two collections (e.g. `a` and `b`) and two groups (`read a, manage b` and `manage a, read b` each with the corresponding permissions). If you now add a User to both groups they will have the issue in one of those collections regardless of which group is used for calculating the permissions.
Author
Owner

@BlackDex commented on GitHub (Jul 10, 2025):

Looking into the proposed fix https://github.com/dani-garcia/vaultwarden/pull/6017 the issue from what I can tell is that we wrongly assumed that we will only store one CollectionGroup for any given collection in the respective HashMap

I think that one permission is still the good endresult, since you can only have one permission of course. But we probably need to fix how we determine that permissions final state. You can't have both read-only and manage rights on the exact same collection. That two groups assign you different rights means we need to consolidate those into one.

Also by checking both HashMaps sequentially and separately from each other the directly assigned permissions will always precede a group permission (which might be okay if it is intentional - but if it's not we should probably rewrite the way we calculate it).

Ill have to check and validate with upstream in a more detailed way to fix this.

@BlackDex commented on GitHub (Jul 10, 2025): > Looking into the proposed fix https://github.com/dani-garcia/vaultwarden/pull/6017 the issue from what I can tell is that we wrongly assumed that we will only store one CollectionGroup for any given collection in the respective HashMap I think that one permission is still the good endresult, since you can only have one permission of course. But we probably need to fix how we determine that permissions final state. You can't have both read-only and manage rights on the exact same collection. That two groups assign you different rights means we need to consolidate those into one. >Also by checking both HashMaps sequentially and separately from each other the directly assigned permissions will always precede a group permission (which might be okay if it is intentional - but if it's not we should probably rewrite the way we calculate it). Ill have to check and validate with upstream in a more detailed way to fix this.
Author
Owner

@stefan0xC commented on GitHub (Jul 10, 2025):

@BlackDex Yep. I just wanted to document my findings in case we want to tackle the issue again. And while I agree that the combined_permissions is correct for the groups I think that it might be better to do that consolidation in the Collection::to_json_details() function because if we traverse both HashMaps for the given collection we can maybe calculate the calculations in one pass (if we assume that a more permissive entitlement from a group should trump a more restrictive permission that has been directly assigned).

@stefan0xC commented on GitHub (Jul 10, 2025): @BlackDex Yep. I just wanted to document my findings in case we want to tackle the issue again. And while I agree that the `combined_permissions` is correct for the groups I think that it might be better to do that consolidation in the `Collection::to_json_details()` function because if we traverse both HashMaps for the given collection we can maybe calculate the calculations in one pass (if we assume that a more permissive entitlement from a group should trump a more restrictive permission that has been directly assigned).
Author
Owner

@BlackDex commented on GitHub (Jul 10, 2025):

@BlackDex Yep. I just wanted to document my findings in case we want to tackle the issue again. And while I agree that the combined_permission is correct for the groups I think that it might be better to do that consolidation in the Collection::to_json_details() function because if we traverse both HashMaps for the given collection we can maybe calculate the calculations in one pass (if we assume that a more permissive entitlement from a group should trump a more restrictive permission that has been directly assigned).

Yes, it's better to have that in one location which is shared indeed.

@BlackDex commented on GitHub (Jul 10, 2025): > [@BlackDex](https://github.com/BlackDex) Yep. I just wanted to document my findings in case we want to tackle the issue again. And while I agree that the `combined_permission` is correct for the groups I think that it might be better to do that consolidation in the `Collection::to_json_details()` function because if we traverse both HashMaps for the given collection we can maybe calculate the calculations in one pass (if we assume that a more permissive entitlement from a group should trump a more restrictive permission that has been directly assigned). Yes, it's better to have that in one location which is shared indeed.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/vaultwarden#5837