Support Library
Mixed Content: Scripts Loaded over Plain HTTP
An HTTPS page is only as secure as everything it loads. When the page pulls a script, stylesheet or frame from a plain http:// address, that piece can be read and changed on the way, and browsers block it.
The short answer
Change every http:// resource URL on your HTTPS pages to https://, or host the file yourself. As a safety net, add the upgrade-insecure-requests directive to your Content-Security-Policy so browsers request any leftovers over HTTPS.
What goes wrong
Browsers sort mixed content into two kinds. Active content, such as scripts, stylesheets, iframes and fetch requests, can change the page and is always blocked. Passive content, such as images, audio and video, is now upgraded to HTTPS automatically by current Chrome, Edge and Firefox, and blocked if the upgrade fails.
How DNS Panopticon detects it
Security Posture reads the HTML of your HTTPS homepage and counts <script> tags whose src starts with http://. The result appears on the Website Application Security card.
| Finding | Severity | When it appears |
|---|---|---|
| Scripts load over plain http | Medium | At least one script on the HTTPS homepage is loaded from an http:// address, and the page’s Content-Security-Policy does not include upgrade-insecure-requests. |
The check covers scripts written into the homepage HTML. Scripts added later by other scripts, and stylesheets, frames and images, are not counted, so check the browser console as well.
How to find it yourself
Open the page, then the browser’s developer tools (F12) and the Console tab. Blocked requests show messages such as “Mixed Content: The page at ‘https://example.com/’ was loaded over HTTPS, but requested an insecure script ‘http://…’. This request has been blocked.”
| Command | What it shows |
|---|---|
| curl -s https://example.com | grep -o 'src="http://[^"]*"' | Every http:// src attribute in the page HTML (macOS, Linux, WSL). |
| (Invoke-WebRequest -Uri https://example.com -UseBasicParsing).Content | Select-String -Pattern 'src="http://[^"]*"' -AllMatches | ForEach-Object { $_.Matches.Value } | The same search in Windows PowerShell. |
| curl -sI https://example.com | Whether a content-security-policy header already includes upgrade-insecure-requests. |
Why it matters
- Full page takeover. A script can read form fields, change links, redirect the visitor or load more code. If an attacker can replace it, they effectively control the page, padlock and all.
- Broken features. Because browsers block the request, whatever the script does, such as a chat widget, analytics, a payment form or a menu, silently stops working for every visitor.
- Older clients. Some embedded web views and old browsers do not block mixed content, so their users get the insecure version.
How to fix it
- Switch the URL to https://. Almost every CDN and third-party service supports HTTPS at the same address. Open the https:// version of the URL in a browser to confirm.
- Host it yourself if the provider has no HTTPS version, or replace the service.
- Search templates and content, not just the page you noticed. In a CMS, old posts and settings often store http:// URLs. On WordPress, WP-CLI can rewrite them: wp search-replace 'http://example.com' 'https://example.com' --dry-run, then run it again without --dry-run.
- Add upgrade-insecure-requests as a safety net. It tells the browser to request every http:// resource on the page over HTTPS instead. It only helps when the resource is actually available over HTTPS.
- Pin third-party scripts with Subresource Integrity (an integrity attribute) so the browser refuses a file that has been changed.
| Platform | Adding upgrade-insecure-requests |
|---|---|
| nginx | add_header Content-Security-Policy "upgrade-insecure-requests" always; |
| Apache | Header always set Content-Security-Policy "upgrade-insecure-requests" |
| Cloudflare | Automatic HTTPS Rewrites rewrites http:// links in HTML it can upgrade |
| HTML only | <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> in the page head |
If you already send a Content-Security-Policy, add the directive to it rather than sending a second header.
FAQ
Are images over http:// a problem too?
Less so. Current browsers upgrade images, audio and video to HTTPS automatically and block them if that fails, so the risk is a broken image rather than a hijacked page. They are still worth fixing.
Should I use protocol-relative URLs like //cdn.example.net/file.js?
No longer. They were a workaround from when sites served both HTTP and HTTPS. Now that the page should always be HTTPS, write https:// explicitly.
Does upgrade-insecure-requests fix mixed content on its own?
It hides the problem when the resource is also available on HTTPS, which is usually the case. If it is not, the upgraded request fails and the feature still breaks, so fix the URLs too.
Why does DNS Panopticon still flag a script that my browser blocks?
Because the page still asks for it. Blocking keeps visitors safe in modern browsers, but the feature is broken and older clients may still load it.
Sources and further reading
- W3C: Mixed Content: the specification browsers follow
- MDN: Mixed content
- MDN: CSP upgrade-insecure-requests
- web.dev: What is mixed content?
- Chromium Blog: No more mixed messages about HTTPS: Chrome’s autoupgrade and blocking plan
- MDN: Subresource Integrity
- WP-CLI: wp search-replace