Mixed Active Content on HTTPS Pages
Issue No: 185
Category: HTTP Security Headers
Issue Type: Issue
Priority: Critical
Description
HTTPS pages must not load active resources (scripts, stylesheets, iframes) over HTTP. Browsers block mixed active content entirely, breaking page functionality and removing the HTTPS security indicator, directly harming user trust and site credibility.
Crawler Constraint: The XeoPix crawler detects mixed content declared in raw HTML only. Resources injected by JavaScript or referenced inside external CSS files via
url()cannot be detected without execution or fetching external stylesheets. The triggers only fire when HTTP-scheme URLs are found in static HTML resource attributes on an HTTPS page.
How Do We Capture It
Where to Find
Mixed active content (browser blocks):
<script src="http://cdn.example.com/app.js"></script>
<link rel="stylesheet" href="http://cdn.example.com/style.css">
<iframe src="http://widget.example.com/embed"></iframe>
<object data="http://cdn.example.com/plugin.swf"></object>
<embed src="http://cdn.example.com/player.swf">
Mixed passive content (browser warns):
<img src="http://cdn.example.com/image.jpg">
<video src="http://media.example.com/clip.mp4"></video>
<audio src="http://media.example.com/track.mp3"></audio>
<source src="http://media.example.com/clip.webm">
Extraction Flow
- Issue an HTTP GET to the target URL; follow any redirects to the final URL.
- Check the scheme of the final resolved URL.
- If the final URL scheme is
http, setpage_is_https = FALSEand skip all further analysis — mixed content only applies to HTTPS pages. - If the final URL scheme is
https, setpage_is_https = TRUEand continue. - Parse the full raw HTML document.
- Collect resource URLs from active resource tags:
<script>—srcattribute<link>—hrefattribute (whererelisstylesheet,preload,modulepreload, or empty)<iframe>—srcattribute<object>—dataattribute<embed>—srcattribute
- Filter for URLs where the scheme is exactly
http://(nothttps://, not protocol-relative//). - Collect these into
active_mixed_content_urls; count and sethas_active_mixed_content. - Collect resource URLs from passive resource tags:
<img>—srcattribute<video>—srcattribute<audio>—srcattribute<source>—srcattribute
- Filter for URLs where the scheme is exactly
http://. - Collect these into
passive_mixed_content_urls; count and sethas_passive_mixed_content.
Note: Protocol-relative URLs (//cdn.example.com/...) inherit the page scheme. On HTTPS pages they resolve to https:// and are not mixed content. Do not flag protocol-relative URLs.
Validation Logic
The crawler validates:
- Whether the final resolved URL uses the HTTPS scheme.
- Whether any active resource attribute in the HTML contains an absolute
http://URL. - Whether any passive resource attribute contains an absolute
http://URL. - That
has_active_mixed_contentandhas_passive_mixed_contentare only set to TRUE whenpage_is_https = TRUE.
How to Get It
Crawler should:
- Resolve the final URL; check scheme — skip analysis entirely if
http. - Parse full raw HTML document.
- Collect
src/href/datavalues from active tags (script, link, iframe, object, embed). - Filter for
http://scheme; store as active mixed content list. - Collect
srcvalues from passive tags (img, video, audio, source). - Filter for
http://scheme; store as passive mixed content list. - Set BOOLEAN flags based on whether each list is non-empty.
What to Store
| Field | Type | Comment |
|---|---|---|
page_is_https | BOOLEAN | Whether the final resolved crawled URL uses the HTTPS scheme |
has_active_mixed_content | BOOLEAN | Whether any active resource (script, stylesheet, iframe, object, embed) loads over HTTP on this HTTPS page; always FALSE when page_is_https = FALSE |
active_mixed_content_urls | TEXT[] | List of http:// URLs found in active resource attributes on an HTTPS page |
active_mixed_content_count | INT | Number of distinct active mixed content URLs found |
has_passive_mixed_content | BOOLEAN | Whether any passive resource (img, video, audio, source) loads over HTTP on this HTTPS page; always FALSE when page_is_https = FALSE |
passive_mixed_content_urls | TEXT[] | List of http:// URLs found in passive resource attributes on an HTTPS page |
passive_mixed_content_count | INT | Number of distinct passive mixed content URLs found |
Condition for Trigger
The following trigger rules evaluate mixed content on HTTPS pages. Both has_active_mixed_content and has_passive_mixed_content are only set to TRUE when page_is_https = TRUE, so these triggers cannot fire on HTTP pages.
-
Trigger Rule 1: Active Mixed Content Detected
- Target Field:
has_active_mixed_content - Evaluation Logic:
= TRUE - Severity: CRITICAL
- Diagnostic Message: "Active mixed content was detected: one or more scripts, stylesheets, or iframes load over HTTP on this HTTPS page. Browsers block these resources entirely, causing page functionality to break silently. Upgrade all active resource URLs from http:// to https://."
- Target Field:
-
Trigger Rule 2: Passive Mixed Content Detected
- Target Field:
has_passive_mixed_content - Evaluation Logic:
= TRUE - Severity: WARNING
- Diagnostic Message: "Passive mixed content was detected: one or more images, videos, or audio resources load over HTTP on this HTTPS page. Browsers display a downgraded security indicator and may block these resources in future versions. Upgrade all passive resource URLs from http:// to https://."
- Target Field:
Sources
- MDN — Mixed content
- MDN — How to fix a website with blocked mixed content
- W3C — Mixed Content specification
- OWASP — Transport Layer Protection Cheat Sheet
- Google — Fixing mixed content
Long Description
Mixed content occurs when an HTTPS page loads resources from HTTP origins. The browser has established a verified TLS connection to the page, but then initiates unencrypted HTTP connections for individual resources. An attacker in a network-adjacent position (public Wi-Fi, ISP, CDN) can intercept and modify those HTTP resources in transit before they reach the browser.
Why active mixed content is critical:
Active mixed content can read or modify the page DOM and execute arbitrary JavaScript. A man-in-the-middle attacker who intercepts an HTTP script response can inject any code into the page, with full access to the user's session, cookies, and form inputs. For this reason, all modern browsers (Chrome, Firefox, Safari, Edge) block active mixed content entirely — the resource never loads.
Why passive mixed content is a warning:
Passive mixed content cannot execute code but can be inspected in transit. An attacker can observe which images the user loads (revealing page context) or modify images before delivery. Chrome now also blocks passive mixed content (images over HTTP on HTTPS pages) in many cases. Even where not blocked, the HTTPS padlock is replaced with a warning icon.
Resource type classification:
| Type | Tags | Browser behavior |
|---|---|---|
| Active | script, link (CSS/preload), iframe, object, embed | Blocked — resource does not load |
| Passive | img, video, audio, source | Warned — may load but padlock is removed |
Common failure scenarios:
1. Legacy Hardcoded HTTP URLs in HTML Templates
A CMS or site generator hardcodes http://static.example.com for asset URLs in HTML templates. When the site is migrated to HTTPS, the templates are not updated and all assets continue to be referenced over HTTP.
2. User-Generated Content With HTTP Image URLs
A blog, forum, or e-commerce platform allows users to embed images from external sources. User-submitted http:// image URLs become passive mixed content on the HTTPS page.
3. Third-Party Script Loaded Over HTTP
An embedded chat widget, analytics snippet, or advertisement SDK is added via an HTTP <script> tag. The script is blocked by the browser, the widget fails silently, and the padlock is removed.
4. Protocol-Relative URLs Not Flagged
URLs beginning with // (e.g., //cdn.example.com/script.js) are protocol-relative. On HTTPS pages they resolve to https://cdn.example.com/script.js and are safe. This check does not flag protocol-relative URLs.
5. Dynamic or CSS-Injected Mixed Content Not Detected
Resources loaded by JavaScript at runtime or referenced via url() in external CSS files cannot be detected from raw HTML. These are known constraints of static crawl-based analysis.
How to Fix
Upgrade all HTTP-scheme resource URLs to HTTPS in the HTML source:
- Replace
http://withhttps://for every resource URL in HTML templates, CMS media settings, theme files, and page builders. - Verify that the HTTPS endpoint for each resource returns the correct content and an HTTP 200 response.
- For third-party resources, use the
https://URL provided by the vendor. If the vendor does not offer HTTPS, replace the resource with an HTTPS-capable alternative. - For resources under your own domain or CDN, ensure TLS is enabled and the asset is accessible over HTTPS.
- Use protocol-relative URLs (
//cdn.example.com/...) only when a resource must serve both HTTP and HTTPS pages from the same URL. On HTTPS pages, protocol-relative URLs automatically use HTTPS. - Add
Content-Security-Policy: upgrade-insecure-requestsas an additional server-side safeguard. This instructs browsers to automatically upgrade HTTP resource requests to HTTPS before the request is made, providing a runtime safety net while source URLs are being fixed. This header does not replace fixing the source URLs — it is a supplemental measure only.