Issue: Optional asset proxy mode for servers with incorrect MIME configuration
Summary
Some WordPress installations serve extracted package assets directly from the uploads directory. This works well when the web server has a correct MIME configuration, but it can break packages when JavaScript files are returned as text/plain while X-Content-Type-Options: nosniff is enabled.
In that case browsers refuse to execute the scripts, even though the files exist and the HTTP status is 200.
Observed behavior
On an affected site, package HTML loads correctly through the REST content endpoint, but JavaScript assets loaded directly from the uploads directory are rejected by the browser.
Example response:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
X-Content-Type-Options: nosniff
The file body is valid JavaScript, but Chromium/Firefox reject it because strict MIME checking is enabled by nosniff.
Typical browser error:
Refused to execute script because its MIME type ('text/plain') is not executable, and strict MIME type checking is enabled.
Root cause
The plugin currently relies on the web server to serve static assets from the extracted package directory with the correct MIME type.
That is the fastest path and should remain the default. However, on servers where the uploads/files location is configured with an incomplete or incorrect MIME map, JavaScript files may be returned as text/plain.
Proposed solution
Add an optional setting to serve package assets through the plugin content proxy instead of linking them directly from uploads.
Suggested setting:
[ ] Serve package assets through the WordPress proxy
Suggested help text:
Use this option only if your web server returns incorrect MIME types for package assets, for example JavaScript files served as text/plain. When enabled, CSS, JavaScript, fonts, images and other package files are served through WordPress so the plugin can send explicit Content-Type headers. This can reduce performance because requests are handled by PHP instead of being served directly by the web server.
This text should be translatable.
Implementation notes
- Keep direct uploads URLs as the default for performance.
- Add a settings checkbox, for example
proxy_assets or similar.
- When enabled, rewrite package asset URLs to the existing content proxy endpoint, not only HTML files.
- The proxy should keep strict path validation:
- validate package hash;
- reject path traversal;
- resolve paths with
realpath();
- ensure the resolved path stays inside the extracted package directory;
- allow only known package asset extensions.
- The proxy should emit explicit MIME types for at least:
.js, .mjs
.css
.json
.svg
.png, .jpg, .jpeg, .gif, .webp, .ico
.woff, .woff2, .ttf, .otf, .eot
.mp3, .mp4, .webm, .ogg, .ogv, .wav
.pdf
- CSS
url(...) references also need rewriting when CSS is served through the proxy, otherwise relative paths such as url(img/foo.svg) may resolve relative to the proxy endpoint path instead of the package CSS file.
- External URLs such as YouTube embeds,
https://, data:, blob:, protocol-relative URLs and anchors should not be proxied.
Acceptance criteria
Issue: Optional asset proxy mode for servers with incorrect MIME configuration
Summary
Some WordPress installations serve extracted package assets directly from the uploads directory. This works well when the web server has a correct MIME configuration, but it can break packages when JavaScript files are returned as
text/plainwhileX-Content-Type-Options: nosniffis enabled.In that case browsers refuse to execute the scripts, even though the files exist and the HTTP status is
200.Observed behavior
On an affected site, package HTML loads correctly through the REST content endpoint, but JavaScript assets loaded directly from the uploads directory are rejected by the browser.
Example response:
The file body is valid JavaScript, but Chromium/Firefox reject it because strict MIME checking is enabled by
nosniff.Typical browser error:
Root cause
The plugin currently relies on the web server to serve static assets from the extracted package directory with the correct MIME type.
That is the fastest path and should remain the default. However, on servers where the uploads/files location is configured with an incomplete or incorrect MIME map, JavaScript files may be returned as
text/plain.Proposed solution
Add an optional setting to serve package assets through the plugin content proxy instead of linking them directly from uploads.
Suggested setting:
Suggested help text:
This text should be translatable.
Implementation notes
proxy_assetsor similar.realpath();.js,.mjs.css.json.svg.png,.jpg,.jpeg,.gif,.webp,.ico.woff,.woff2,.ttf,.otf,.eot.mp3,.mp4,.webm,.ogg,.ogv,.wav.pdfurl(...)references also need rewriting when CSS is served through the proxy, otherwise relative paths such asurl(img/foo.svg)may resolve relative to the proxy endpoint path instead of the package CSS file.https://,data:,blob:, protocol-relative URLs and anchors should not be proxied.Acceptance criteria
application/javascriptor another valid JavaScript MIME type.text/css.url(...)references are correctly resolved relative to the CSS file location.