How to load remote image in content script without violating add-on policy?

I just recently submitted my first extension for review and had it rejected for this reason:

“We don’t allow add-ons to use remote images because they can create serious security vulnerabilities. Please insert those images locally from your add-on code.”

My addon turns Youtube into an audio only platform and overlays a thumbnail onto the Youtube player by creating an element and setting the .src to an image from the img.youtube.com domain

Example of the element created(from js) <img id="playerOverlay" src="https://img.youtube.com/vi/hTvJoYnpeRQ/maxresdefault.jpg" height="360" width="640">

My question is this:

  1. Is it really the case that I cannot use remote images what so ever?
  2. What is the security risk?
  3. Where is the policy documentation that forbids this?
  4. Is there an allowed alternative technique to use a remote image, for example something like "image downloaded as blob via XHR, converted to an extension URI and then injected as <img src="moz-extension:...">" OR encode the image into base64 and inject using <img src="data:image/jpeg;base64........."
  5. Is it true that not one firefox add-on references a remote image?(find this hard to believe)

Remote resources (eg images, fonts, CSS, etc) can be used for tracking (it will be allowed if the resource is from the same domain as the page the user is on).

Therefore, if you are on youtube.com you can use images from that domain, or images that youtube.com uses (like ytimg.com) since they are already present.

That exclude images with identifying data such as www.example.com/this.jgp?user_url=****

There are limited occasions that remote iamges can be allowed, for example MAP type addons that show a remote MAP location.

All static images should be included in the addon as it serves no purpose to request them over HTTP/S.

1 Like

Hi erosman, thanks for the reply.
You say I can use images from the same domain, my content script is injected into tabs on youtube.com and loads an image from the subdomain img.youtube.com with the format https://img.youtube.com/vi/{VIDEO_ID}/maxresdefault.jpg you can see it in my code here
So you can see I’m sourcing the image from the same domain as my content script, so why was my extension rejected?

That exclude images with identifying data such as www.example.com/this.jgp?user_url=****

I see, I don’t believe this url format fits that description, does it?
https://img.youtube.com/vi/hTvJoYnpeRQ/maxresdefault.jpg
The characters between /vi/ and /maxresdefault.jpg is the ID of the Youtube video loaded, the video id is retrieved from tab.url of a webrequest listener

By identifying strings I mean those that pass, URL, domain, username, pass, affiliate code etc

That section of the code looks OK to me if the image is inserted into a youtube.com page.

PS. Popups and sidebars etc are not part of any page.

I had a quick look at the code. It could be made more straight forward. It would be more efficient to inject tab-exec.js as a function from manifest.json and run it when needed from background.js

You should also limit the permission to youtube (not "<all_urls>")

1 Like

You’re right, I’ve updated the manifest permissions to reflect the code.

Are you an official AMO reviewer? So if I quote you as saying a remote image from the same domain as my content script is allowed, would that hold any water when I resubmit my extension?

If I did it that way (I used to) I would need to set up message listeners just to send one string from background.js to tab-exec.js, I find it much simpler to use tabs.executeScript with the code: string parameter to send a string to my content script.

yes… that is the response that I use (although others may have different views :wink: )

Not necessarily. In one of my addons (FoxyImage), I insert a function (via manifest.json) into pages that doesn’t auto-run … then use tabs.executeScript to run that function

Imagine:

content.js

function aFunc(a, b) {
  // some code
}

background.js

chrome.tabs.executeScript({code : 'aFunc(something, other);'}, ...

So you use the tabs.executeScript to run a function that is waiting in content.js and the return value from the function will be sent to the tabs.executeScript :slight_smile:

Thanks for the clarification, my add-on was approved :+1:
https://addons.mozilla.org/en-US/firefox/addon/youtubeaudio/