something I don't think I've ever seen explained is whether there's any situation where it's safe to set "Access-Control-Allow-Origin: *" other than "if your site literally never serves any private data"

(I often hear "don't do it" which is fair I guess, but also like the Mastodon API intentionally sets Access-Control-Allow-Origin: * and that's extremely useful)

also is there any name for the attack(s) that setting "Access-Control-Allow-Origin: *" might expose you to? i feel like it's so much easier to talk about security stuff in terms of the specific threats we're trying to avoid, but I can't think of the name for it

(edit: I think it's CSRF)

huh I'm not sure if this is true but this post argues that it's generally fine to set Access-Control-Allow-Origin: * (as long as you don't set Access-Control-Allow-Credentials, and as long as the API is public and not on an intranet) https://advancedweb.hu/is-access-control-allow-origin-star-insecure/
Is Access-Control-Allow-Origin: * insecure?

Disabling a security feature is usually a bad thing. In this case, it's fine

@b0rk What that page misses is consideration of the question: is there any chance the content on my site could be used maliciously?

That is, if my site allows user-uploaded content, how sure am I that there's zero chance my site might end up hosting something malicious?

Which, of course, has nothing to do with credentials.

Or, I guess, put another way: yes, credential and identity exfiltration is one vulnerability addressed by CORS (and CSP), but it's not the only one.

One specific example here is a scenario where a site allows users to upload their own avatar image, say in PNG format. But instead of sending a PNG, the user uploads a JS file but sends its content-type: image/png. The site thinks "it's just an image" and doesn't bother to check that the content is actually valid.

If that site then has ACAO: *, it has just become a hosting service for malicious code.

Write-up for an SVG alternative to this attack: https://www.cloudflare.com/cloudforce-one/research/svgs-the-hackers-canvas/

SVGs: the hacker’s canvas

Cloudforce One research reveals a surge in phishing attacks using SVG files, exploiting their scriptable nature to bypass detection. Discover how this overlooked vector poses a growing threat to email security.

@ricko @b0rk

I assume that you mean that some other site might now include that malicious piece of js via <script src=foo> tag. If so, (a) doesn't that work in absence of A-C-A-O too? (b) in what scenarios an attacker can cause another site to embed that <script> tag, but neither an inline script tag, nor a <script src=bar> tag that points at any of the pastebin sites that exist on the web?

@robryk @b0rk

doesn't that work in absence of A-C-A-O?

As a script or img, yes. (Presuming poor CSP setup.) But we've also seen plenty of naive user agents which don't pay attention to the content-type and will instead content sniff. MSIE was a classic example. We're seeing similar vulnerabilities in AI agents.

in what scenarios an attacker can cause another site to embed that script tag, but neither an inline script tag, nor a script src=bar tag that points at any of the pastebin sites

I could see a scenario like this:

  • Someone creates a friends-of-mastodon.example
  • They set up the CSP to allow content from bad-cors.example because they want to use avatars or embedded toots.
  • They also allow users to submit content, such as their username.
  • They don't adequately sanitize one of the inputs, allowing script or img tags to slip through, like that username.
  • Now, simply viewing that username causes malicious JS to run, because it all looks "allowed".
  • @ricko @b0rk Your reply got truncated, presumably on the `<` character.

    @robryk @b0rk Updated. I brought it back.

    Amusingly, all the text I typed was still there. I'm now feeling very raised-eyebrow about the content sanitization in mastodon.

    @ricko @b0rk I would wager that this is the typical behaviour of markdown renderers, where selected html tags are passed through and others are skipped in some way.

    IMO a worse issue around rendering in fediverse is that a post can contain its contents in multiple formats (e.g. plain text, markdown, html...) and it's not entirely obvious which one will be rendered (so it can look differently depending on what does the rendering).

    Edit: Ah, and re making toots that appear differently to different people: also the fallback for quote toots is a good way to cause toots to appear differently on instances without quote toot support, not even mentioning the possibility of an instance sending different contents of the same toot to different inboxes.
    @robryk @b0rk Hahaha. Fair. All the pain of multi-part MIME. It's like we didn't learn the lesson the first time with HTML email.
    @ricko @b0rk And with mailing lists being able to sow confusion. (I am still surprised that I haven't seen sending-different-toots-to-different-instances used maliciously on fedi, only as part of "<your instance> is the best instance" jokes.)
    @robryk @b0rk hahahaha. There was an entire second half to that toot, which got chopped off because I didn't wrap the <script> tags in backticks. One sec, lemme retype it all.
    @ricko @b0rk

    But all that still works even with no A-C-A-O header anywhere, because it relies on <script src=foo>, no? I still don't see how including `A-C-A-O: *` makes things worse.

    @robryk @b0rk You're right, for that specific example. I ran out of characters and oversimplified.

    In today's world of SPAs, it's just as likely that this could be done without script tags, just some field where the user enters a URL. For example, "use this image at this URL as the cover art for this album" or "as the start for this generative AI thing".

    That URL gets fetched, sent back as JS (through poor sanitization on bad-cors.example), and then the * tells the browser to allow it to run.

    That still requires some exceptionally poor code on the fetch side of things, but that's always the case with vulnerabilities: they don't have to be likely, just possible, because the infinite monkeys which make up the Internet will eventually trip across the specific very bad combination.

    @ricko @b0rk

    So the situation is that the vulnerable side is doing cross-origin fetch from a user-provided URL, expecting an image/piece of text/something of that nature, gets a piece of JS or an SVG with embedded JS and (due to being vulnerable) runs it? And then the reason why it matters that it comes from _this particular_ site is that the user is providing the URL, so the attacker must find a non-suspicious looking one.

    Thanks, this is a scenario that does sound possible (and I have no good intuitions about what kinds of issues are likely to appear in today's SPAs; I only worked on non-web security).

    Also, this sounds similar to using (lack of) A-C-A-O as a "hotlinking prevention": lack of A-C-A-O here serves as a kind of weak repudiation of contents (it feels like CSP would benefit from a feature where a resource could be repudiated for CSP-related purposes).

    @robryk @b0rk Yeah, in a sense, A-C-A-O: * is effectively telling the world: "I attest anything accessible from bad-cors.example to be safe to use absolutely anywhere".

    Which is reasonable only when bad-cors.example has seriously vetted all the ways they expect their content to be used, and considered all the ways it might be abused.

    When you introduce user-managed content into that, those stories get significantly more complex. But if, for example, I wrote up some JS which I wanted to share with the world and I wanted to be usable anywhere, and it was always under my control, then * is perfectly fine and reasonable.

    @robryk @b0rk

    it feels like CSP would benefit from a feature where a resource could be repudiated for CSP-related purposes

    CSP does have a repudiation feature where you can really lock it down. Safelist instead of blocklist.

    https://content-security-policy.com/hash/

    Many modern build systems will generate these by default and embed them in the HTML which loads the JS for the app. (You can send them in the HTTP headers, but that's actually very rare, as now you need to synchronize your headers with specific content versions, which is a pain.)

    While these hashes are also useful for Sub-Resource Integrity (tamper detection), they work just as well for attestation. "When loading this app, these are the hashes of the exact list of scripts, css, images, etc, which I expect to be loaded and used."

    I just built a system for this a few months ago at my previous employer. It's fiddly to set up, but it really helps raise visibility of when something changes in your build/deploy system, whether intentional or not.

    CSP Hash Examples and Guide

    Implementing a hash with Content Security Policy (CSP)

    @ricko @b0rk I didn't mean that feature, but rather a response header that would mean "if you want to evaluate any CSP policy on this resource, it should fail".