Web Vault: Cache-Control Headers are incorrectly being sent in requests instead of server responses #2264

Closed
opened 2025-10-09 17:54:10 +03:00 by OVERLORD · 4 comments
Owner

Originally created by @Algebro7 on GitHub.

I started playing around with bitwarden_rs today and noticed that cache-control: no-cache, max-age=0 and pragma: no-cache are being sent in the request headers instead of in the response, so they are effectively doing nothing. Example:

GET /api/sync?excludeDomains=true HTTP/1.1
Host: <redacted>
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://<redacted>
device-type: 10
authorization: Bearer <redacted>
cache-control: no-cache, max-age=0
pragma: no-cache
origin: https://<redacted>
DNT: 1
Connection: close

I also recommend setting the no-store directive in addition to no-cache.

Additionally, many responses aren't setting the additional security headers like X-Frame-Options and X-Content-Type-Options referenced in #44 . example from /api/sync:

HTTP/1.1 200 OK
Server: nginx
Date: Mon, 10 Dec 2018 04:46:53 GMT
Content-Type: application/json
Content-Length: 7489
Connection: close
Strict-Transport-Security: max-age=63072000; includeSubDomains
Originally created by @Algebro7 on GitHub. I started playing around with bitwarden_rs today and noticed that `cache-control: no-cache, max-age=0` and `pragma: no-cache` are being sent in the request headers instead of in the response, so they are effectively doing nothing. Example: ``` GET /api/sync?excludeDomains=true HTTP/1.1 Host: <redacted> User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0 Accept: application/json Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: https://<redacted> device-type: 10 authorization: Bearer <redacted> cache-control: no-cache, max-age=0 pragma: no-cache origin: https://<redacted> DNT: 1 Connection: close ``` I also recommend setting the `no-store` directive in addition to `no-cache`. Additionally, many responses aren't setting the additional security headers like `X-Frame-Options` and `X-Content-Type-Options` referenced in #44 . example from /api/sync: ``` HTTP/1.1 200 OK Server: nginx Date: Mon, 10 Dec 2018 04:46:53 GMT Content-Type: application/json Content-Length: 7489 Connection: close Strict-Transport-Security: max-age=63072000; includeSubDomains ```
Author
Owner

@Algebro7 commented on GitHub:

As far as I know, they don't make sense in the API (the only one who may be interesting is the X-Content-Type-Options, but we always set the content type in the API requests, so it won't provide any benefit there).

It is still possible in some browsers (like certain versions of IE) to trigger content sniffing even if the content type is set as application/json. As for cache-control, once again it's true that most browsers won't cache JSON responses, but it's better to just set them and not have to rely on the client.

@Algebro7 commented on GitHub: > As far as I know, they don't make sense in the API (the only one who may be interesting is the X-Content-Type-Options, but we always set the content type in the API requests, so it won't provide any benefit there). It is still possible in some browsers (like certain versions of IE) to trigger content sniffing even if the content type is set as application/json. As for cache-control, once again it's true that most browsers won't cache JSON responses, but it's better to just set them and not have to rely on the client.
Author
Owner

@Algebro7 commented on GitHub:

I was jumping through the codebase and the only reference I can find to the cache-control headers is here in web-vault/app/main.5930681efb99dba78a54.js

            }, n.prototype.fetch = function(n) {
                return "GET" === n.method && (n.headers.set("Cache-Control", "no-cache"), n.headers.set("Pragma", "no-cache")), fetch(n)
            }, n.prototype.send = function(n, l, e, o, r) {

I could be wrong since the issue doesn't happen with the official bitwarden web vault, but I'm guessing this is an upstream issue with the web-vault that we won't be able to fix.

@Algebro7 commented on GitHub: I was jumping through the codebase and the only reference I can find to the cache-control headers is here in `web-vault/app/main.5930681efb99dba78a54.js` ``` }, n.prototype.fetch = function(n) { return "GET" === n.method && (n.headers.set("Cache-Control", "no-cache"), n.headers.set("Pragma", "no-cache")), fetch(n) }, n.prototype.send = function(n, l, e, o, r) { ``` I could be wrong since the issue doesn't happen with the official bitwarden web vault, but I'm guessing this is an upstream issue with the web-vault that we won't be able to fix.
Author
Owner

@dani-garcia commented on GitHub:

I don't know exactly why the web vault is setting those headers in the requests. I haven't noticed the browser caching the server response, so I don't know how useful would adding more headers be.

At the moment, we are only sending the security headers with the web vault resources, the API itself doesn't send them. As far as I know, they don't make sense in the API (the only one who may be interesting is the X-Content-Type-Options, but we always set the content type in the API requests, so it won't provide any benefit there).

@dani-garcia commented on GitHub: I don't know exactly why the web vault is setting those headers in the requests. I haven't noticed the browser caching the server response, so I don't know how useful would adding more headers be. At the moment, we are only sending the security headers with the web vault resources, the API itself doesn't send them. As far as I know, they don't make sense in the API (the only one who may be interesting is the `X-Content-Type-Options`, but we always set the content type in the API requests, so it won't provide any benefit there).
Author
Owner

@dani-garcia commented on GitHub:

I pushed a new commit adding the headers globally, and also added the cache header following what upstream was doing:

  • Api calls don't get cached
  • Web page resources and icons get cached a week
  • The HTML pages themselves get cached for ten minutes.

I pushed this to the admin page branch in case there are any incompatibilities or whatever.

@dani-garcia commented on GitHub: I pushed a new commit adding the headers globally, and also added the cache header following what upstream was doing: - Api calls don't get cached - Web page resources and icons get cached a week - The HTML pages themselves get cached for ten minutes. I pushed this to the admin page branch in case there are any incompatibilities or whatever.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/vaultwarden#2264