Skip to content

Improve docs for new CORS changes in 5.2.1 #5446

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
2 of 4 tasks
Banner-Keith opened this issue Mar 27, 2025 · 34 comments · Fixed by #5510
Closed
2 of 4 tasks

Improve docs for new CORS changes in 5.2.1 #5446

Banner-Keith opened this issue Mar 27, 2025 · 34 comments · Fixed by #5510

Comments

@Banner-Keith
Copy link

Banner-Keith commented Mar 27, 2025

Documentation Is:

  • Missing
  • Needed
  • Confusing
  • Not Sure?

With the change made in the latest version of webpack dev server, there are some CORS changes that need to be made. My first clue something was changed was 403 errors being thrown.

It would be nice to have Access-Control-Allow-Origin documented in the webpack-dev server page on the webpack site and in the readme like the release notes have.

In addition, I found that I needed to add a crossorigin attribute to my script and link tags for the requests to succeed. So that may be good to include as well.

@alexander-akait
Copy link
Member

In addition, I found that I needed to add a crossorigin attribute to my script and link tags for the requests to succeed. So that may be good to include as well.

In basic usage you don't need it and everything will work fine, can you provide your using (maybe reproducible test repo)?

We already have docs about how to use headers, we can't provide all CORS guidelines in our docs, because this topic is quite broad and there are quite a lot of resources on how to set it up

@Banner-Keith
Copy link
Author

I will have to see if I can create a test repo for this. The big one is we are using HtmlWebpackPlugin and HtmlWebpackInjectAttributesPlugin to inject dynamic script and link tags into the HTML. The auto-generated tags will not have the crossorigin attribute by default. So I would assume that anyone using the latest dev server and also using HtmlWebpackPlugin might also experience this issue.

If this isn't something you see being a common issue this ticket can be closed. At least it is searchable here if anyone decides to search issues here and this is useful to them.

@kristof-spaas-hs
Copy link

We are experiencing the same issue, our script are also dynamically injected without the crossorigin attribute by default which causes a 403 being thrown.
Should it not be possible to still make use of a Access-Control-Allow-Origin header?
The newly added middleware does not seem to take the header into account.

@xiaoYown

This comment has been minimized.

@alexander-akait
Copy link
Member

@Banner-Keith Please create reproducible test repo, you should not inject crossorigin in normal usage

@kristof-spaas-hs If you need help please avoid messages like the same, create re reproducible test repo and I will help

@xiaoYown It means you have problems with your env, because Access-Control-Allow-Origin should work

@MattiasJa
Copy link

We resolved the 403 issue for chunks loading by setting below :

output: {
crossOriginLoading: 'anonymous',
},

@fish-face
Copy link

fish-face commented Mar 31, 2025

We have also run into an issue with all our bundles being inaccessible over the dev server as of this release. We have 'Access-Control-Allow-Origin': '*', and this is returned if I manually curl -i URLs which are being blocked by the browser.

Other workarounds mentioned here do not work for us; neither adding crossorigin to resource tags nor crossOriginLoading: 'anonymous' to module.exports.output.

Our situation is using webpack_loader with Django.

I have limited knowledge of CORS details, but it seems to me that the change is in fact wrong. Isn't Sec-Fetch-Mode: no-cors specifically supposed to permit cross origin GET requests such as fetching stylesheets, which this change makes no allowance for?

In any case I would like to suggest that this change be reverted for the time being. We are talking about a dev server; a cross-site origin issue should not cause problems, right? Is there a compelling reason to make this a breaking change in a patch release?? Loads of downstream projects caught this breaking change automatically because there was no major version bump indicating backwards-incompatibility. If it turns out that this change is correct, contrary to what I said above, you can always cut a major release?

@riconnon
Copy link

riconnon commented Apr 1, 2025

I'm also very confused by this change and very frustrated by the breakage.
I'm working on a project with allowedHosts set to "all" and Access-Control-Allow-Origin header set to "*" and the dev server is not blocking requests, so clearly the change is not working as intended.

Unless I'm very much mistaken it's not normal to block requests on the server side for Cross-Origin protection since Cross-Origin resource loading protections are for the client and implemented by the client.

Especially since this is a DEV server it is definitely an incredibly odd decision to make a breaking change in a bugfix release that resolves a, questionable at best, "security issue".

Was any threat modelling done to determine the severity of this "bug" before the fix was merged and released as a bugfix? If it is considered a security bug is there a CVE assigned?

@martijnpieters
Copy link

martijnpieters commented Apr 1, 2025

Besides downgrading to version 5.2.0, you could also consider disabling the newly added cross-origin-header-check middleware in version 5.2.1.

That could be done by setting the devServer.setupMiddlewares value in the webpack config to something like:

setupMiddlewares: (middlewares) => {
  return middlewares.filter(middleware => middleware.name !== "cross-origin-header-check");
}

As mentioned later: use it at your own risk, If you are working in a secure environment you have nothing to worry about, but if not you may end up with a vulnerability.

@riconnon
Copy link

riconnon commented Apr 1, 2025

@martijnpieters that's very helpful, thanks, but it's a workaround at best...

I'd really like to understand how, with this feature in place, I am supposed to configure this to work given that allowedHosts: "all" and "Access-Control-Allow-Origin": "*", as implied by the changelog messages which is the only documentation of this new behaviour, is not sufficient.

@fish-face
Copy link

Other googling of this issue found people proxying all connections to their app through the webpack dev server so that nothing was cross-origin... Maybe it is simply not anticipated that cross-origin requests to the dev server happen? Doesn't align with the documentation of crossOriginLoading though.

But yes, hopefully a maintainer can enlighten us soon about the anticipated threat this is supposed to protect against and the intended behaviour, which will determine if this is a behaviour bug or missing docs.

@martijnpieters
Copy link

martijnpieters commented Apr 1, 2025

@martijnpieters that's very helpful, thanks, but it's a workaround at best...

I'd really like to understand how, with this feature in place, I am supposed to configure this to work given that allowedHosts: "all" and "Access-Control-Allow-Origin": "*", as implied by the changelog messages which is the only documentation of this new behaviour, is not sufficient.

@riconnon Yes, it's a workaround. But there's no other way to disable this (new) piece of code:

        if (
          headers["sec-fetch-mode"] === "no-cors" &&
          headers["sec-fetch-site"] === "cross-site"
        ) {
          res.statusCode = 403;
          res.end("Cross-Origin request blocked");
          return;
        }

So for version 5.2.1, settings like allowedHosts: "all" and "Access-Control-Allow-Origin": "*" will not change anything about the returned 403.

@Hypnosphi
Copy link

Hypnosphi commented Apr 1, 2025

a cross-site origin issue should not cause problems

I can imagine some malicious website requesting resources from some commonly used ports on localhost and basically stealing your source code. So unless you're only working on open source projects that can be problematic

@riconnon
Copy link

riconnon commented Apr 1, 2025

a cross-site origin issue should not cause problems

I can imagine some malicious website requesting resources from some commonly used ports on localhost and basically stealing your source code. So unless you're only working on open source projects that can be problematic

The cross-origin protections in place in my browser will prevent that already. I'm not aware of a need for this to be implemented server-side.

@riconnon
Copy link

riconnon commented Apr 1, 2025

@martijnpieters that's very helpful, thanks, but it's a workaround at best...
I'd really like to understand how, with this feature in place, I am supposed to configure this to work given that allowedHosts: "all" and "Access-Control-Allow-Origin": "*", as implied by the changelog messages which is the only documentation of this new behaviour, is not sufficient.

@riconnon Yes, it's a workaround. But there's no other way to disable this (new) piece of code:

    if (
      headers["sec-fetch-mode"] === "no-cors" &&
      headers["sec-fetch-site"] === "cross-site"
    ) {
      res.statusCode = 403;
      res.end("Cross-Origin request blocked");
      return;
    }

So for version 5.2.1, settings like allowedHosts: "all" and "Access-Control-Allow-Origin": "*" will not change anything about the returned 403.

Very frustrating. The changelog says:

unless allowed by Access-Control-Allow-Origin header

and

unless configured by allowedHosts

so these two statements are very actively misleading if that doesn't actually work.

@alexander-akait
Copy link
Member

alexander-akait commented Apr 2, 2025

@riconnon

Especially since this is a DEV server it is definitely an incredibly odd decision to make a breaking change in a bugfix release that resolves a, questionable at best, "security issue".

Yes, we have two reports how and where code was stolen. Don't forget you can have very sensitive date in your source code.

Was any threat modelling done to determine the severity of this "bug" before the fix was merged and released as a bugfix? If it is considered a security bug is there a CVE assigned?

Yes, and CVE already requested

The cross-origin protections in place in my browser will prevent that already. I'm not aware of a need for this to be implemented server-side.

Unfortunately only Google Chrome (and chromium based and only new versions)

Very frustrating. The changelog says:

So for version 5.2.1, settings like allowedHosts: "all" and "Access-Control-Allow-Origin": "*" will not change anything about the returned 403.

Maybe you are using proxies somewhere? Without example I can't say what is wrong with your env, but it should work

Does this work for you - #5446 (comment)?

@martijnpieters

It is not a workaround, it is a solution, but you use it at your own risk, If you are working in a secure environment you have nothing to worry about, but if not you may end up with a vulnerability.

@alexander-akait
Copy link
Member

So feel free to send an example of your env, so I will look and will say is it dangerous case or not, and how to fix a problem, alternative - we can use the allowedHosts option logic for sec-fetch-* and don't set them if you have allowed host or using the all value, it should be fixed most of cases, but I really want to see an example where our current logic is not working

@martijnpieters
Copy link

@alexander-akait Thanks for your elaborate response!

I have also modified my earlier comment to include the warning.

@fish-face
Copy link

You can find our setup at https://gitlab.com/hunter2.app/hunter2/-/blob/master/webpack.dev.js?ref_type=heads

There's no proxying; django is listening (in development) on 8080 and webpack is listening on 4000.

However, I've worked out that my initial test of the crossorigin resource attribute was wrong; I have now got it working with this. But Django's webpack integration does not do this by default, so this is a big pain.

I'm trying to understand what you've been saying about the allowedHosts and Access-Control headers. Neither of these has any effect in the case the new middleware is acting in, as far as I can see: Access-Control headers only apply when the request is controlled by CORS, which is not the case when sec-fetch-mode is no-cors, and the host is the same whether the request is cross-origin or not.

The remedy, as I understand it, is to:

  1. ensure your resources have the crossorigin attribute
  2. set the correct Access-Control headers

So the documentation needs to reflect this. If this change weren't out yet, it would be reasonable to insist that this documentation be referenced in the changelog.

However, isn't this what Cross-Origin-Resource-Policy (supported in all major browsers since 2020) is designed for? Using that, instead of this middleware, would allow the browser to understand what is happening and surface a reasonable error message, further aiding the effort of developers caught by surprise.

So here are my concrete requests:

  1. Document that the default behaviour in 5.2.1 requires crossorigin on resources if you are not proxying webpack-dev-server and other servers onto a single origin
  2. Document that not all bundle renderers do this for you yet
  3. Document the existence of this middleware and how to disable it
  4. Introduce a new change which replaces this middleware with the default addition of Cross-Origin-Resource-Policy: same-site to outgoing headers. Note that same-site is more relaxed than same-origin and all of localhost, no matter the port, counts as same-site, which is exactly the behaviour we would probably want.
  5. Replace 3 with documenting this default header, so people can change that if they wish.

@Banner-Keith
Copy link
Author

Like @fish-face I am also not proxying my backend with webpack dev server. So the pages are served from one localhost port and webpack dev server is on another port.

@niklasschaeffer
Copy link

This is by no means a minor change though. You should have communicated this way better. A lot of ppl rely on the dev-server-package.

@alexander-akait
Copy link
Member

@fish-face You still can use such solution - #5446 (comment)

In fact, this is exactly the usage that we wanted to fix, because it is potentially unsafe and can lead to your code being stolen, yes, now it requires more settings in such cases. I am not against improving the documentation and you can send a PR to improve it, unfortunately the topic of CORS is very large and I simply cannot describe all possible use cases, this is open source and I do not always have free time for a deep and complete documentation.

In the basic use of the dev server, you will never encounter such problems, in exotic cases the dev server now requires more settings to keep your code safe.

Introduce a new change which replaces this middleware with the default addition of Cross-Origin-Resource-Policy: same-site to outgoing headers. Note that same-site is more relaxed than same-origin and all of localhost, no matter the port, counts as same-site, which is exactly the behaviour we would probably want.

Replace 3 with documenting this default header, so people can change that if they wish.

It is still unsafe

@rodoabad
Copy link

rodoabad commented Apr 3, 2025

@alexander-akait , is it to my understanding that the reason for this change was because of a vulnerability report?

That's what I've read from the v5.2.1 release notes.

I think where most of the frustration comes from us users was it wasn't properly documented on how to fix this error.

@fish-face
Copy link

In fact, this is exactly the usage that we wanted to fix, because it is potentially unsafe and can lead to your code being stolen, yes, now it requires more settings in such cases. I am not against improving the documentation and you can send a PR to improve it, unfortunately the topic of CORS is very large and I simply cannot describe all possible use cases, this is open source and I do not always have free time for a deep and complete documentation.

In the basic use of the dev server, you will never encounter such problems, in exotic cases the dev server now requires more settings to keep your code safe.

You will appreciate that our code is open source, so we are not worried about it being exposed. I'm trying to work with you to provide a solution for people who are working on closed source projects that doesn't introduce more hard to debug, undocumented difficulties. Being told that this, the only way I know of to use webpack together with django, is "exotic" does not help, especially when this "exotic" use case is the situation the change was supposed to help with.

What appears to have happened is that you've decided one way of using webpack (any way where you don't run an entire site with it?) is dangerous and have therefore prevented people from using it in that way unless they go through some convoluted steps that you haven't told anyone about and indeed have told people in the changelog, commit message and this thread things which have no effect.

So while I appreciate the restrictions on open source projects and want to help you, if you're going to do the "PRs welcome" shtick which we've all done at one time or another, you would get a better response if you would first indicate that the current information being given out (to people who go digging in github) is wrong, and make some recognition that you've cost people time, instead of trying to fob people off that their situation - the only situation affected - is "exotic". Being in an exotic situation does not make "Access-Control-Allow-Origin should work" accurate.

It is still unsafe

That's not a very useful response. I'm trying to approach this with a positive attitude, but it is hard to swallow being told "we broke your use case, we will give you wrong advice on how to fix it, tell you your situation is niche, not recognise good versioning practices, not engage with attempts to improve the situation... by the way, PRs welcome." Sorry if that's not nice to hear, but... same.

So, trying again, why does CORP not solve the issue you're trying to solve?

@PeteH32
Copy link

PeteH32 commented Apr 4, 2025

I have not tested this, but reviewing the code change that introduced this new behavior (Merge commit from fork), it seems like here are examples that will or will not get blocked (403 response). I think most developers using webpack-dev-server would be okay, since they should be able to set the same "site" for both the web page and the server, where "site" is as defined by the "Sec-Fetch-Site" header specification, where ports can be different as long as rest is same.

The left is the client web page (e.g. Chrome browser). The right is the server (webpack-dev-server). NOTE: Malicious site "f00.com" is different than "foo.com".

Web page                 Server                Result
http://foo.com    ==>    http://foo.com        200 OK because same "origin"
http://f00.com    ==>    http://foo.com        403 fail because domain is different, so not same "site"
http://foo.com    ==>    http://foo.com:2992   200 OK because same "site"
https://foo.com   ==>    http://foo.com:2992   403 fail because scheme/protocol is different, so not same "site"

@fish-face
Copy link

@PeteH32 if I recall/understand correctly that won't work for local development, because any two origins on localhost are viewed by the browser as different sites. I can't find good sources for this, but it's my observation and my recollection from the last time I had to deal with CORS and local development.

@alopix
Copy link

alopix commented Apr 7, 2025

I think this should be better documented and configuration should be added/enabled in order to bypass this.
We are using localhost.domain.com and localhost.domain.othertld in order to run different versions for local markets dynamically—whereas static assets are always served from the .com domain (allowing to reuse sign in cookies from the "live" system).
This change breaks being able to load static assets from a single localhost domain and only this thread surfaced the workaround solution.
Since the dev environment is only started once without knowing which market you will work on (and often you will test multiple) there is no way to dynamically configure the statics assets domain either.

@PeteH32
Copy link

PeteH32 commented Apr 7, 2025

@alopix ,
Does the configuration described by @martijnpieters (in above post here), work in your situation? Before the maintainers can expose that as a configuration setting (i.e. simpler to use), I'm guessing they need verification it actually works for the various situations people are running. Your testing results would be valuable.

@alopix
Copy link

alopix commented Apr 8, 2025

@PeteH32 yes the posted workaround works, but that hardly is a configuration. It completely gets rid of the feature instead of allowing (as others have mentioned) proper configuration to make situations like this work safely (which still blocking other types of access).

andersk added a commit to andersk/zulip that referenced this issue Apr 15, 2025
This middleware in webpck-dev-server 5.2.1 appears to be intended to
plug some undisclosed browser-specific vulnerability that allows
stealing code from closed-source projects.

webpack/webpack-dev-server#5446 (comment)
webpack/webpack-dev-server#5446 (comment)

Signed-off-by: Anders Kaseorg <[email protected]>
andersk added a commit to andersk/zulip that referenced this issue Apr 15, 2025
This middleware in webpack-dev-server 5.2.1 appears to be intended to
plug some undisclosed browser-specific vulnerability that allows
stealing code from closed-source projects.

webpack/webpack-dev-server#5446 (comment)
webpack/webpack-dev-server#5446 (comment)

Signed-off-by: Anders Kaseorg <[email protected]>
andersk added a commit to zulip/zulip that referenced this issue Apr 15, 2025
This middleware in webpack-dev-server 5.2.1 appears to be intended to
plug some undisclosed browser-specific vulnerability that allows
stealing code from closed-source projects.

webpack/webpack-dev-server#5446 (comment)
webpack/webpack-dev-server#5446 (comment)

Signed-off-by: Anders Kaseorg <[email protected]>
theofficialvedantjoshi pushed a commit to theofficialvedantjoshi/zulip that referenced this issue May 2, 2025
This middleware in webpack-dev-server 5.2.1 appears to be intended to
plug some undisclosed browser-specific vulnerability that allows
stealing code from closed-source projects.

webpack/webpack-dev-server#5446 (comment)
webpack/webpack-dev-server#5446 (comment)

Signed-off-by: Anders Kaseorg <[email protected]>
@karolyi
Copy link

karolyi commented May 4, 2025

Disclaimer: I was the one who added the integrity calculation and crossorigin attribute to django-webpack-loader.

I was hit by this 'bugfix' too, and spent half of the day investigating in the source code as to why I'm getting 403 errors.

@fish-face the bad news is, even if you enable the crossorigin attribute on the rendered tags, HMR still won't work, it's how I bumped into this bug. I've modified my code in django-webpack-loader temporarily to emit the crossorigin even without the integrity tags (because currently the only way is to use them together), and while page loads worked, HMR (hot module replacement) didn't. The newly generated chunks have gotten a 403 as they were requested with the

Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: cross-site

headers.

I didn't read all the comments here to see what security bug this fixed, but my assumption is that when being used in local development, many people relied on the previous state.

Here's to hoping someone manages to unfuck this.

@karolyi
Copy link

karolyi commented May 5, 2025

Coming back to this today (yesterday I was out of fucks to give), the fix for this problem with keeping the 'bugfix' is a quick one:

diff --git a/lib/Server.js b/lib/Server.js
index 6e208128..2fef252b 100644
--- a/lib/Server.js
+++ b/lib/Server.js
@@ -1983,6 +1983,17 @@ class Server {
        * @returns {void}
        */
       middleware: (req, res, next) => {
+        if (
+          this.options.allowedHosts === 'all'
+          || (
+            typeof this.options.headers === 'object'
+            && !Array.isArray(this.options.headers)
+            && this.options.headers['Access-Control-Allow-Origin'] === '*'
+          )
+        ) {
+          // Skip when headers or allowedHosts configured
+          return next()
+        }
         const headers =
           /** @type {{ [key: string]: string | undefined }} */
           (req.headers);

I can issue a MR if so wished.

@fish-face
Copy link

It is still unsafe

@alexander-akait why is setting Cross-Origin-Resource-Policy unsafe? What are the circumstances in which this middleware prevents something bad happening, which CORP does not? And what is it that happens?

tatablack added a commit to tatablack/leaner-coffee-powerup that referenced this issue May 6, 2025
@dkarlovi
Copy link

Besides downgrading to version 5.2.0, you could also consider disabling the newly added cross-origin-header-check middleware in version 5.2.1.

That could be done by setting the devServer.setupMiddlewares value in the webpack config to something like:

setupMiddlewares: (middlewares) => {
return middlewares.filter(middleware => middleware.name !== "cross-origin-header-check");
}
As mentioned later: use it at your own risk, If you are working in a secure environment you have nothing to worry about, but if not you may end up with a vulnerability.

This works for me, but allowHosts all should basically mean the same thing, it makes no sense to lock down the dev server this much if the developers have explicitly allowed themselves to access it.

@alexander-akait
Copy link
Member

alexander-akait commented Jun 2, 2025

@dkarlovi I will improve this soon, CORS changes will respect allowedHosts, so you will need allowedHosts: ['localhost'] or allowedHosts: ['foo.com']

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.