X-Content-Type-Options header blocks h5p scripts because of wrong MIME type


  1. After adding X-Content-Type-Options header with the nosniff option, scripts from the h5p plugin were blocked because of wrong MIME types
  2. Wordpress 4.9.5
  3. Desktop
  4. Chrome, Firefox
  5. H5P plugin Version 1.10.1
  6. InteractiveVideo 1.17
  7. Browser console errors:

Mozilla Firefox:

Loading failed for the <script> with source “.../files/h5p/cachedassets/995b0307c8eeea52e64f45853a0ad7a842695b3d.js”.
Unable to find constructor for: H5P.InteractiveVideo 1.17 h5p.js:861:5
TypeError: instance is undefined

Google chrome:

Refused to execute script from '.../files/h5p/cachedassets/7de4395….js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled


It seems that the h5p plugin doesn't work with my newly added X-Content-Type-Options header. I dont know if my webserver is misconfigured or the problem lies with h5p itself. Help would be much appreciated.

icc's picture

Your web server isn't sending the correct "Content-Type: ..." header.
How you fix this depends on which web server you're running. Most web servers have a separate mime types file where they include all of the file types. If you are running on a shared hosting environment with Apache one solution could be to add the following to your .htaccess files: AddType application/javascript .js

Note that some "security" plugins may generate this file for you in the uploads folder where they deny access to .js files or their mime type as a precaution.

You can double check the content type header using online tools or the command line tool curl -I http://yourdomain/file.js

I'm facing the same problem as "cm141" but on my installation (multisite blog) it says it's a "image/js" mime type. 

I'm pretty sure it's not a problem of missconfiguration as any other js files are delivered correctly and the mime type settings on the server are correct. Any other ideas?

regards Pascal 

icc's picture

There is no PHP or plugin code running in between the web server and the file on the disk. The web server is the one checking the file extension and sending the content type header + the file to the client. I am pretty certain that your web servers are misconfigured, please double check all configuration and .htaccess files in parent directories.

I have done a few tests to find out more.

Setting define('H5P_DISABLE_AGGREGATION', true); has shown that scripts from the libraries in wp-content/blogs.dir/blogname/files/... get served with wrong headers, while scripts from wp-content/plugins/h5p/... are served correctly.

I run nginx, so there are no .htaccess files inside any directories. I also searched manually just to be sure. My include statement for mime.types in nginx.conf is inside my default server block with root directory set to the root for my wp multisite. I also made sure that mime.types included the entry for javascript.

A general

location ~ .js {
    add_header  Content-Type    application/x-javascript;

in the server block did nothing.

I just did the update to 1.10.2 and we are still facing the same problem. 

I also tripple-checked the settings on the server down to the cachedasset folder and it looks good to me (see attached screenshot). 

icc's picture

Hi, could you please verify the header using a tool like cURL? E.g.

curl -I https://h5p.org/sites/default/files/h5p_mimetype.png 2>/dev/null |grep -Fi Content-Type

Or you can use an online tool like this:

Just enter the URL that is failing and you should see the Content-Type header returned by your web server.

curl -I https://mysite/blogname/files/h5p/libraries/H5P.InteractiveVideo-1.17/di... 2>/dev/null |grep -Fi Content-Type
Content-Type: text/plain

Firefox network monitor

Connection    keep-alive
Content-Length    74358
Content-Security-Policy-Report-Only    default-src 'self' https://sec…a:; report-uri /csp-report.php
Content-Type    text/plain
Date    Tue, 12 Jun 2018 12:15:09 GMT
ETag    "d2c1d2e02f78dfcc6fd2d62054e40277"
Expires    Thu, 12 Aug 2021 22:01:49 GMT
Last-Modified    Mon, 13 Nov 2017 10:59:24 GMT
Referrer-Policy    strict-origin-when-cross-origin
Server    nginx/1.12.2
Strict-Transport-Security    max-age=31536000
X-Frame-Options    SAMEORIGIN
X-Powered-By    PHP/5.4.16
X-XSS-Protection    1; mode=block

I found the problem. My wordpress multisite installation is old and uses the wp-includes/ms-files.php rewrite rule for user files in /blogname/files/. The code in ms-files.php also checks MIME types with wp_check_filetype, which uses get_allowed_mime_types() to get the list of allowed MIME types. And get_allowed_mime_types() unsets javascript if the user doesnt have unfiltered_html allowed.

After modifying get_allowed_mime_types() to not unset javascript for user files the correct MIME types were send. Allowing js for users is not secure, so I should probably remove my ms-files.php dependency.

To pascalCH, maybe you have a similar problem. Because if ms-files.php cant find a MIME type, it does the following:

$mimetype = 'image/' . substr( $file, strrpos( $file, '.' ) + 1 );

header( 'Content-Type: ' . $mimetype );

So you could get "image/js".

icc's picture

Ah, thank you for sharing. I have not heard about this before.

Thank you cm141! This fixed the problem on my wordpress installation as well.

The downside is, we now have a manually patched wordpress-installation. I tried to move the fix to the function.php file in my theme, but I was not successfull with this.

Considering that my wp installation was already manually modified before this, I didn't try doing the fix without changing core. I use git with merge to update wordpress. Maybe you could write a plugin which resets the javascript mime type with a hook.

I also tested that users still can't upload js. So it would seem that wp is still secure in that aspect, even with the modification. That means I am leaving things as they are instead of trying to get rid of ms-files.php.

For everyone having problems with ms-files and wanting to get rid of it: https://halfelf.org/2012/dumping-ms-files/
Fair warning, this doesn't seem to be trivial.

BV52's picture

Hi cm141,

Once again thank you for sharing this, we really appreciate it :-)