Videos in v3 extension results in Content Security “Refused to load media” error

1,668 views
Skip to first unread message

Jack

unread,
Aug 11, 2021, 5:34:29 PM8/11/21
to Chromium Extensions
Hi - I have a Chrome Extension that when clicked displays a video on the page like: 

    <video width="320" height="240" controls>
      <source src="https://example.com/video.mp4" type="video/mp4">
    </video>

The video doesn't load on the page and in the console I see this error:

   Refused to load media from 'https://example.com/video.mp4' because it violates the following Content Security Policy directive: "media-src 'self' blob:

In my Manifest (version3) I've tried several versions of the below but nothing works. Does anyone know how to resolve this error so that the video can load? Any help is much appreciated - thanks.

      "content_security_policy": {
        "extension_pages": "script-src 'self'; object-src 'self'; media-src * blob: https://example.com/*"
      },

Simeon Vincent

unread,
Aug 12, 2021, 11:15:55 AM8/12/21
to Jack, Chromium Extensions
My CSP is a little rusty; I think the way you're specifying the host URL may be incorrect. It looks like you're currently using the extension match pattern syntax, but CSP sources just take a domain. Give this a shot.

  "extension_pages": "script-src 'self'; object-src 'self'; media-src * blob: example.com"

Simeon - @dotproto
Chrome Extensions DevRel


--
You received this message because you are subscribed to the Google Groups "Chromium Extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extens...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-extensions/ae54e618-de5e-471e-aa09-15c981444013n%40chromium.org.

Jack

unread,
Aug 12, 2021, 9:46:55 PM8/12/21
to Chromium Extensions, Simeon Vincent, Chromium Extensions, Jack
Thanks Simeon - unfortunately the issue is still occurring. 

I wonder if the problem is that I'm trying to do this on Twitter.com? Perhaps they're the ones blocking the request and not the chrome extension?  

Cuyler Stuwe

unread,
Aug 12, 2021, 9:49:59 PM8/12/21
to Jack, Chromium Extensions, Simeon Vincent
He said “on the page”, which is ambiguous, but my presumption due to context is that he’s trying to do it on the Twitter page. In that case, your only option is to block or modify CSP headers for Twitter end route (which IIRC is more complicated because it uses a service worker you might still need to unregister first).

Simeon Vincent

unread,
Aug 12, 2021, 10:15:10 PM8/12/21
to Cuyler Stuwe, Jack, Chromium Extensions
In that case it would be a CORS issue, not a CSP one, right? If the error states that the request violates the following Content Security Policy directive: "media-src 'self' blob:", then it's possible this is an extension CSP bug.

Jack, could you share a reduced demo of the issue you're experiencing? That might us understand the error and, if it is a bug, help Chrome engineers fix it.

Simeon - @dotproto
Chrome Extensions DevRel

Cuyler Stuwe

unread,
Aug 12, 2021, 10:28:58 PM8/12/21
to Chromium Extensions, Simeon Vincent, Jack, Chromium Extensions, Cuyler Stuwe
No, it would most certainly be a CSP issue.

Here's their entire CSP header (it's one of the biggest ones I've seen):

content-security-policy:
connect-src 'self' blob: https://*.giphy.com https://*.pscp.tv https://*.video.pscp.tv https://*.twimg.com https://api.twitter.com https://api-stream.twitter.com https://ads-api.twitter.com https://aa.twitter.com https://caps.twitter.com https://media.riffsy.com https://pay.twitter.com https://sentry.io https://ton.twitter.com https://twitter.com https://upload.twitter.com https://www.google-analytics.com https://app.link https://api2.branch.io https://bnc.lt wss://*.pscp.tv https://vmap.snappytv.com https://vmapstage.snappytv.com https://vmaprel.snappytv.com https://vmap.grabyo.com https://dhdsnappytv-vh.akamaihd.net https://pdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://dwo3ckksxlb0v.cloudfront.net ; default-src 'self'; form-action 'self' https://twitter.com https://*.twitter.com; font-src 'self' https://*.twimg.com; frame-src 'self' https://twitter.com https://mobile.twitter.com https://pay.twitter.com https://cards-frame.twitter.com https://accounts.google.com/; img-src 'self' blob: data: https://*.cdn.twitter.com https://ton.twitter.com https://*.twimg.com https://analytics.twitter.com https://cm.g.doubleclick.net https://www.google-analytics.com https://www.periscope.tv https://www.pscp.tv https://media.riffsy.com https://*.giphy.com https://*.pscp.tv https://*.periscope.tv https://prod-periscope-profile.s3-us-west-2.amazonaws.com https://platform-lookaside.fbsbx.com https://scontent.xx.fbcdn.net https://scontent-sea1-1.xx.fbcdn.net https://*.googleusercontent.com https://imgix.revue.co; manifest-src 'self'; media-src 'self' blob: https://twitter.com https://*.twimg.com https://*.vine.co https://*.pscp.tv https://*.video.pscp.tv https://*.giphy.com https://media.riffsy.com https://dhdsnappytv-vh.akamaihd.net https://pdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://dwo3ckksxlb0v.cloudfront.net; object-src 'none'; script-src 'self' 'unsafe-inline' https://*.twimg.com https://www.google-analytics.com https://twitter.com https://app.link https://apis.google.com/js/platform.js https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js 'nonce-OTQwZmMzODUtYWQ1MS00NWZhLWFhOTYtYjZlMTI4N2YwOTll'; style-src 'self' 'unsafe-inline' https://*.twimg.com; worker-src 'self' blob:; report-uri https://twitter.com/i/csp_report?a=O5RXE%3D%3D%3D&ro=false

Simeon Vincent

unread,
Aug 12, 2021, 10:32:11 PM8/12/21
to Cuyler Stuwe, Chromium Extensions, Jack
*sigh* you've successfully nersniped me. I have to make a test extension now.

Simeon - @dotproto
Chrome Extensions DevRel

Cuyler Stuwe

unread,
Aug 12, 2021, 10:43:12 PM8/12/21
to Simeon Vincent, Chromium Extensions, Jack
At a high level, CORS is essentially when the browser pretends that the backend said "no". CSP is when the browser pretends that the frontend said "no". That's the simplest effective way to think about it.

Cuyler Stuwe

unread,
Aug 12, 2021, 10:44:32 PM8/12/21
to Simeon Vincent, Chromium Extensions, Jack
And, on this topic... It would be nice if we had a way to change CSP on-the-fly with extensions, but we can't. The only way you can meaningfully impact a CSP with a Chrome extension is by modifying those headers before putting together the page.

Cuyler Stuwe

unread,
Aug 12, 2021, 10:46:27 PM8/12/21
to Simeon Vincent, Chromium Extensions, Jack
Therefore, making calculated changes to CSP (rather than e.g., throwing the whole thing away) is something we could do with the MV2 WebRequest model that the more opaque/declarative MV3 model disables. If all I want to do is make it so that something not on Twitter's CSP can play inline, I have to throw away their entire CSP header just to do that.

Simeon Vincent

unread,
Aug 13, 2021, 1:28:07 AM8/13/21
to Cuyler Stuwe, Chromium Extensions, Jack
Ah, just came back to this after taking a break and I think I misinterpreted your request, Jack. I assumed that you were attempting to inject resources from example.com (later clarified as twitter.com) into a page inside your extension. If that is what you were after, I've got a demo for you.


But, on re-reading this thread I think you're looking to inject resources from another site on Twitter. As Cuyler said, that will require modifying the page's CSP, which is not currently supported in MV3. 

Simeon - @dotproto
Chrome Extensions DevRel

Jack

unread,
Aug 13, 2021, 7:59:50 AM8/13/21
to Chromium Extensions, Simeon Vincent, Chromium Extensions, Jack, salem...@gmail.com
Simeon & Salem - thanks so much for helping to get to the bottom of the issue! I thought I was losing it for a second there haha. 

Yup, I'm trying to inject resources from another site into Twitter, via MV3, which I now know is unsupported. Assuming there are no MV3 workarounds, I guess I'll have to rewrite my extension in MV2 as video injection is a big part of the extensions use case. 

In MV2, will putting the below in the manifest enable injection?

  "extension_pages": "script-src 'self'; object-src 'self'; media-src * blob: example.com"

Vishnu NUK

unread,
Aug 13, 2021, 8:43:06 AM8/13/21
to Chromium Extensions, Jack, Simeon Vincent, Chromium Extensions, salem...@gmail.com
" I guess I'll have to rewrite my extension in MV2 as video injection is a big part of the extensions use case. "
I think very soon you may need to adapt MV3, Developing new extensions on MV2 right now will be a bad idea. 

Cuyler Stuwe

unread,
Aug 13, 2021, 9:23:03 AM8/13/21
to Chromium Extensions, narayanann...@gmail.com, Jack, Simeon Vincent, Chromium Extensions, Cuyler Stuwe
@Simeon - No, as long as DeclarativeNetRequest works as described in the documentation, he definitely will be able to modify the CSP.

In both MV2 and MV3, the only way to change a CSP is in-flight, by altering the CSP header. It's just that in MV3, since you can't parse this header, you have to be much more heavy-handed with it. MV2 would let you read the network request, so that you could parse the CSP header and replace it with a slightly-tweaked version that adds your own rule into it (while leaving it otherwise intact). In MV3, you can't parse it, so your only option for relaxing the CSP is nuking the CSP header entirely.

Kinda like how the MV3 requirement of restarting service workers over and over goes against the stated goal of "performance", this constraint in network processing ironically makes it more difficult for a trustworthy extension to be "secure". Noble intentions don't really matter in life; All that matters are the outcomes of your actions -- and many of the outcomes of MV3 are working against its stated intents.

@Jack - Look into totally nuking the CSP header with an MV3 extension using the DeclarativeNetRequest API. If that doesn't work as expected, then check Twitter for a service worker, which you might need to unregister and prevent from re-registering (I've done this with a content script). With the WebRequest API, at the very least, there have been problems where a service worker can consume and manipulate a network request such that a browser extension never gets to see that it ever even occurred. It's a headache; I wish browser extensions had first dibs on these kinds of things. Maybe DeclarativeNetRequest works like this, and if so, it would at least be one benefit of it.

Alexei Miagkov

unread,
Aug 13, 2021, 9:53:30 AM8/13/21
to Cuyler Stuwe, Chromium Extensions, narayanann...@gmail.com, Jack, Simeon Vincent
The current Chrome developer docs don't seem to mention this, but I don't think MV3 will let you remove or trim the site's CSP headers.


Cuyler Stuwe

unread,
Aug 13, 2021, 9:59:41 AM8/13/21
to Chromium Extensions, Alex, Chromium Extensions, narayanann...@gmail.com, Jack, Simeon Vincent, Cuyler Stuwe
@Alex - Haha, oh man, you're right. It's even more suffocating than I thought. 😂

Cuyler Stuwe

unread,
Aug 13, 2021, 10:05:07 AM8/13/21
to Chromium Extensions, Cuyler Stuwe, Alex, Chromium Extensions, narayanann...@gmail.com, Jack, Simeon Vincent
I spent so much time in MV2-land needing to discover various quirks about extensions via forum chats like these, Chromium bug trackers, and/or the Chromium source itself.

I had thought that maybe the refresh of the documentation page was turning a new leaf on that, but it seems we're still leaving extremely-important details out from the documentation pages.

Simeon Vincent

unread,
Aug 13, 2021, 10:18:34 AM8/13/21
to Cuyler Stuwe, Chromium Extensions, Alex, narayanann...@gmail.com, Jack
The info I've shared in this group is often based on conversations with my team and double-checking the docs. This conversation made me realize that header modification restrictions are not currently part of the declarativeNetRequest API docs and that I hadn't tried to double check the public docs on this topic until now.

I'll give you that this omission is a bad look, but an important difference between the previous ~6 years and now is that we have people (namely myself and my tech writer counterpart) actively working on documentation. This is very much something I can jump on, or, failing that, lean on other folks to get it fixed. I'll be following up with the eng team today to gather info – already sent a ping. 

Simeon - @dotproto
Chrome Extensions DevRel


Cuyler Stuwe

unread,
Aug 13, 2021, 10:20:46 AM8/13/21
to Chromium Extensions, Simeon Vincent, Chromium Extensions, Alex, narayanann...@gmail.com, Jack, Cuyler Stuwe
Either way is fine by me. The more accurate the docs are, the easier my job is. The more cryptic and obscure the platform is, the more secure my job is. 🤷‍♂️

Simeon Vincent

unread,
Aug 13, 2021, 12:04:26 PM8/13/21
to Cuyler Stuwe, Chromium Extensions, Alex, narayanann...@gmail.com, Jack
Jack, for some your use case got stuck in my brain so ended up putting together a proof of concept for how you could use an extension iframe to inject a video in a page who's CSP rules would otherwise not allow you to. 


Note that you'll need host permissions in order to avoid CORS errors when attempting to load assets in your iframe.

Simeon - @dotproto
Chrome Extensions DevRel

Jack

unread,
Aug 13, 2021, 4:04:22 PM8/13/21
to Chromium Extensions, Simeon Vincent, Chromium Extensions, Alex, narayanann...@gmail.com, Jack, salem...@gmail.com
Simeon I can't thank you enough for taking the time out to put this together! 🙏🙏🙏 

Sincerely appreciated - as a Javascript/Chrome Extension newbie I would've been stuck - thank you! 

Your extension works and I'm now incorporating that injecting-a-video-into-iframe concept into my project. Will let you know how it goes - thanks everyone!

Cuyler Stuwe

unread,
Aug 13, 2021, 4:20:35 PM8/13/21
to Chromium Extensions, Jack, Simeon Vincent, Chromium Extensions, Alex, narayanann...@gmail.com, Cuyler Stuwe
Yeah, this is a great example of when it's good to take a step back and consider whether your problem is an XY Problem.

This is often the case with Chrome Extensions, even more so than with web apps.

In this case, the more general issue was likely something like "I want users to be able to watch video alongside Twitter content" rather than specifically "I want to embed a video". That more-generalized case gives you more room to work with. I have to do this with clients a lot, as they many are nontechnical and have no idea to what extent we can influence the browser -- Often, their initial pitch involves a specific expectation that is 100% impossible within the confines of extensions.

Jack

unread,
Aug 13, 2021, 7:16:16 PM8/13/21
to Chromium Extensions, salem...@gmail.com, Jack, Simeon Vincent, Chromium Extensions, Alex, narayanann...@gmail.com
Just a final update that I now have everything working, thanks to all the wonderful responses from everyone and Simeon's amazing code. 

Thanks for sharing "XY Problem" Salem - really good context for framing technical questions. Love it. 

Cheers everyone and thanks again for the help!

Reply all
Reply to author
Forward
0 new messages