Security - CORS

I learned to love the Same-Origin Policy

Before all of this, I’d more or less equated the Same-Origin Policy with CORS errors, and all of the frustration that they’ve caused me over the years. Now, though, the Same-Origin Policy wasn’t just standing between me and handling a fetch, it was holding up a major work initiative. And I had to explain the situation to bosses who knew even less about security and privacy on the web than I did. Time to learn!

Here’s what I learned:

  • The Same-Origin Policy isn’t a single, simple, rule. And it certainly isn’t == CORS errors.
  • What it is, is a philosophy which has evolved over time, and has been inconsistently implemented across the web platform.
  • In general, what it says is: the fundamental security and privacy boundary of the web is origins. Do you share an origin with something else on the web? You can interact with it however you like. If not, though, you might have to jump through some hoops.
  • Why “might?” Well, a lot of cross-origin interactions are allowed, by default! Generally, when you’re making a website, you can write across origins (by sending POST requests off to whoever you please, via forms). And you can even embed cross-origin resources (iframes, images, fonts, etc) that your site’s visitors will see, right there on your website. But what you can’t do, is look at those cross-origin resources, yourself. You shouldn’t be able to read anything about a cross-origin resource, in your JavaScript, without specially-granted permission (via our old friend, CORS).
  • Here’s the thing that blew my mind the most, once I finally understood it: cross-origin reads are forbidden by default because, as end-users, we all see different world-wide webs, and a website shouldn’t be able to see the rest of the web through its visitors’ eyes. Individuals’ varied local browsing contexts – including, but not limited to, cookies — mean that when I go to, say,, I’m going to see something different than you, when you enter that same URL into your address bar and hit “return.” If other websites could fire off requests to Gmail from my browser, with my cookies, and read the results, well – that would be very, very bad!

So by default: you can do lots of things with cross-origin resources. But preventing cross-origin reads is kind of the whole ballgame. Those defaults are more-or-less what people are talking about when they talk about the “Same-Origin Policy.”

When 7 KB Equals 7 MB

While testing a progressive web app for one of our clients, I bumped into a suspicious error in the browser console:

DOMException: Quota exceeded.

After browsing the app a few more times, it became clear the error would occur after a small number of images were added to the cache storage by the service worker. Looking in the Chrome DevTools Application tab, the cache storage was indeed over capacity.

Chrome DevTools showing over-capacity cache storage.
Chrome DevTools showing over-capacity cache storage.

How could this be? There were only ~15 images in the cache storage. Something was off.

What I found could significantly impact your progressive web app—particularly if you use a CDN on a different domain for your assets.


If you are building a progressive web app and are experiencing bloated cache storage when your service worker caches static assets served from CDNs, make sure the proper CORS response header exists for cross-origin resources, you do not cache opaque responses with your service worker unintentionally, you opt-in cross-origin image assets into CORS mode by adding the crossorigin attribute to the <img> tag.

See the source link for more details.