Open
Description
Is there an existing issue for this?
- I have searched the existing issues
Current Behavior
Current Behavior
Vaultwarden’s diagnostics page reports that X-Frame-Options
and
Content-Security-Policy
are present when they should not be for 2FA-related API calls.
Issue Details
- These headers persist on
/api/two-factor
despite usingproxy_hide_header
. - This causes iframe-based authentication methods (such as Duo 2FA) to fail.
- The issue is consistently reported in the Vaultwarden diagnostics page.
Example Output from Vaultwarden Diagnostics:
2FA Connector calls:
Header: 'x-frame-options' is present while it should not
Header: 'content-security-policy' is present while it should not
### Expected Behavior
## Expected Behavior
The `vaultwarden.subdomain.conf.sample` file should properly handle the removal of
`X-Frame-Options` and `Content-Security-Policy` for all **2FA-related API calls**
to ensure iframe-based authentication (e.g., Duo 2FA) functions correctly.
### Why This Matters
- Some authentication providers require iframes to function properly.
- These headers prevent **iframe-based 2FA login methods from working**.
- Vaultwarden’s **diagnostics page** confirms these headers **should not be present**.
- The issue persists **even after applying `proxy_hide_header` on known 2FA endpoints**.
### Steps To Reproduce
1. Set up Vaultwarden behind SWAG using the default `vaultwarden.subdomain.conf.sample`.
2. Enable 2FA (Duo or other iframe-based authentication methods).
3. Try to authenticate using 2FA.
4. Check Vaultwarden’s diagnostics page:
- **URL:** [https://vaultwarden.domain.com/admin/diagnostics](https://vaultwarden.domain.com/admin/diagnostics)
- **It shows:**
```plaintext
2FA Connector calls:
Header: 'x-frame-options' is present while it should not
Header: 'content-security-policy' is present while it should not
-
Run
curl
to verify headers:curl -I https://vaultwarden.domain.com/api/two-factor
-
Expected Behavior:
X-Frame-Options
andContent-Security-Policy
should be removed.
-
Actual Behavior:
- The headers persist, breaking 2FA authentication.
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!: true
- 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: false
Config & Details (Generated via diagnostics page)
Show Config & Details
Environment settings which are overridden: SIGNUPS_ALLOWED, INVITATIONS_ALLOWED, ADMIN_TOKEN
Failed HTTP Checks:
2FA Connector calls:
Header: 'x-frame-options' is present while it should not
Header: 'content-security-policy' is present while it should not
Config:
{
"_duo_akey": "***",
"_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": "/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": "api-22fc8a48.duosecurity.com",
"duo_ikey": "DIXORW9SNE6071KVE7NL",
"duo_skey": "***",
"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": "/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": "King Paging",
"invitations_allowed": true,
"ip_header": "X-Real-IP",
"job_poll_interval_ms": 30000,
"log_file": "/logs/vaultwarden.log",
"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": 5242880,
"org_creation_users": "",
"org_events_enabled": false,
"org_groups_enabled": false,
"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": true,
"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": false,
"signups_domains_whitelist": "",
"signups_verify": true,
"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": "King's Vaultwarden",
"smtp_host": "**************",
"smtp_password": "***",
"smtp_port": 465,
"smtp_security": "force_tls",
"smtp_ssl": null,
"smtp_timeout": 15,
"smtp_username": "*************************",
"templates_folder": "data/templates",
"tmp_folder": "data/tmp",
"trash_auto_delete_days": 30,
"trash_purge_schedule": "0 5 0 * * *",
"use_sendmail": false,
"use_syslog": false,
"user_attachment_limit": 1048576,
"user_send_limit": 524288,
"web_vault_enabled": true,
"web_vault_folder": "web-vault/",
"yubico_client_id": "72859",
"yubico_secret_key": "***",
"yubico_server": null
}
Environment
OS: unraid 7.0.1
How Docker service was installed: Unraid Community Apps
SWAG Version: 3.3.0
Vaultwarden Version: v1.33.2
Cloudflare Proxy: Yes
CPU architecture
x86-64
Docker creation
docker run \
-d \
--name='swag' \
--net='proxynet' \
--pids-limit 2048 \
-e TZ="America/Chicago" \
-e HOST_OS="Unraid" \
-e HOST_HOSTNAME="UNRAID" \
-e HOST_CONTAINERNAME="swag" \
-e 'URL'='kingpaging.com' \
-e 'VALIDATION'='dns' \
-e 'SUBDOMAINS'='wildcard' \
-e 'CERTPROVIDER'='' \
-e 'DNSPLUGIN'='cloudflare' \
-e 'PROPAGATION'='' \
-e 'EMAIL'='[REDACTED]' \
-e 'ONLY_SUBDOMAINS'='false' \
-e 'EXTRA_DOMAINS'='' \
-e 'STAGING'='false' \
-e 'DISABLE_F2B'='' \
-e 'SWAG_AUTORELOAD'='' \
-e 'SWAG_AUTORELOAD_WATCHLIST'='' \
-e 'DOCKER_MODS'='linuxserver/mods:swag-maxmind|linuxserver/mods:swag-cloudflare-real-ip' \
-e 'MAXMINDDB_USER_ID'='[REDACTED]' \
-e 'PUID'='99' \
-e 'PGID'='100' \
-e 'UMASK'='022' \
-e 'MAXMINDDB_LICENSE_KEY'='[REDACTED]' \
-p '443:443/tcp' \
-p '80:80/tcp' \
-p '8089:8089/tcp' \
-p '8003:8003/tcp' \
-v '/mnt/cache/appdata/swag':'/config':'rw' \
--cap-add=NET_ADMIN 'lscr.io/linuxserver/swag'
Container logs
[mod-init] Running Docker Modification Logic
[mod-init] Adding linuxserver/mods:swag-maxmind to container
[mod-init] Downloading linuxserver/mods:swag-maxmind from lscr.io
[mod-init] Installing linuxserver/mods:swag-maxmind
[mod-init] linuxserver/mods:swag-maxmind applied to container
[mod-init] Adding linuxserver/mods:swag-cloudflare-real-ip to container
[mod-init] Downloading linuxserver/mods:swag-cloudflare-real-ip from lscr.io
[mod-init] Installing linuxserver/mods:swag-cloudflare-real-ip
[mod-init] linuxserver/mods:swag-cloudflare-real-ip applied to container
[migrations] started
[migrations] 01-nginx-site-confs-default: skipped
[migrations] 02-swag-old-certbot-paths: skipped
[migrations] done
───────────────────────────────────────
██╗ ███████╗██╗ ██████╗
██║ ██╔════╝██║██╔═══██╗
██║ ███████╗██║██║ ██║
██║ ╚════██║██║██║ ██║
███████╗███████║██║╚██████╔╝
╚══════╝╚══════╝╚═╝ ╚═════╝
Brought to you by linuxserver.io
───────────────────────────────────────
To support the app dev(s) visit:
Certbot: https://supporters.eff.org/donate/support-work-on-certbot
To support LSIO projects visit:
https://www.linuxserver.io/donate/
───────────────────────────────────────
GID/UID
───────────────────────────────────────
User UID: 99
User GID: 100
───────────────────────────────────────
Linuxserver.io version: 3.3.0-ls369
Build-date: 2025-03-11T17:21:22+00:00
───────────────────────────────────────
using keys found in /config/keys
Variables set:
PUID=99
PGID=100
TZ=America/Chicago
URL=[Redacted]
SUBDOMAINS=wildcard
EXTRA_DOMAINS=
ONLY_SUBDOMAINS=false
VALIDATION=dns
CERTPROVIDER=
DNSPLUGIN=cloudflare
EMAIL=[Redacted]@gmail.com
STAGING=false
Using Let's Encrypt as the cert provider
SUBDOMAINS entered, processing
Wildcard cert for [Redacted] will be requested
E-mail address entered: [Redacted]@gmail.com
dns validation via cloudflare plugin is selected
Certificate exists; parameters unchanged; starting nginx
The cert does not expire within the next day. Letting the cron script handle the renewal attempts overnight (2:08am).
**** adding libmaxminddb to package install list ****
[pkg-install-init] **** Installing all mod packages ****
fetch http://dl-cdn.alpinelinux.org/alpine/v3.21/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.21/community/x86_64/APKINDEX.tar.gz
(1/1) Installing libmaxminddb (1.9.1-r0)
Executing busybox-1.37.0-r12.trigger
OK: 182 MiB in 223 packages
Applying the maxmind mod...
Applied the maxmind mod
[custom-init] No custom files found, skipping...
[ls.io-init] done.
Server ready
Metadata
Metadata
Assignees
Labels
No labels
Type
Projects
Status
Issues