1. Knowledge base
  2. Findings
Check: web.content.mixed_active

Fixing mixed active content on HTTPS pages by upgrading subresources

A page served over HTTPS is only as trustworthy as everything it loads. If the HTML arrives over TLS but a script, stylesheet or iframe inside it is fetched from an http:// URL, that one request is unprotected, and the page is no longer reachable only over encrypted transport. This article covers what the finding means, why it is rated medium, how to remove the cleartext references, and how to confirm the fix on the next scan.

What mixed active content is

The W3C Mixed Content specification (https://www.w3.org/TR/mixed-content/) splits insecure subresources into two groups:

  • Optionally blockable content is passive: images, audio and video. A tampered image can mislead a user, but it cannot execute code in the page.
  • Blockable content is active: scripts, stylesheets, iframes, fetch and XHR targets, web workers, fonts, and <object>/<embed> resources. These can read or rewrite the page, and the specification says user agents should block them on a secure page.

This finding is about the second group. It fires when an HTTPS page references active subresources over cleartext.

Typical causes:

<!-- Hard-coded scheme left over from before the HTTPS migration -->
<script src="http://cdn.example.net/vendor/analytics.js"></script>
<link rel="stylesheet" href="http://static.example.com/theme.css">
<iframe src="http://widgets.example.org/booking"></iframe>

Other sources are database content with absolute http:// URLs, a CMS "site URL" setting that was never switched to https://, third-party tags that inject further http:// scripts at runtime, and application code that calls an http:// API endpoint from JavaScript.

Why an attacker cares

Anyone on the network path can modify cleartext traffic: a hostile Wi-Fi access point, a compromised router, an ISP-level injector. If your page requests http://cdn.example.net/vendor/analytics.js, the attacker answers that request with their own script, and the browser runs it with the full privileges of your origin. That script can read session data from the DOM, rewrite the login form, add a keylogger, or redirect to a phishing page. The padlock still shows, because the top-level document was delivered securely.

Modern browsers usually block this content, and some try to upgrade it automatically. That is why the severity is medium and not high. In the common case the visible damage is a broken page: a missing script, an unstyled layout, or a dead widget. The risk stays real for three reasons:

  • Blocking behaviour differs between browsers, versions, embedded webviews and enterprise-managed clients.
  • The spec treats blocking as the user agent's job, so your site's security depends on the visitor's client and not on your configuration.
  • Auditors read it as a failure of the claim that the site is served only over encrypted transport. It also weakens HSTS, since a policy that forces HTTPS for the page is contradicted by the page's own references.

The cost to an organization has two parts. One is the incident risk of script injection on a page that may handle logins or payments. The other is the compliance and support cost of an audit finding, plus broken features that users report as outages.

How the scanner detects and rates it

The scanner loads the page over HTTPS, follows redirects, and inspects the HTML it receives. It checks the attributes that cause a fetch of active content: src on script and iframe, href on stylesheet links, and data on object elements. Any whose resolved URL uses the http scheme is flagged. Protocol-relative URLs resolve to https on an HTTPS page and are not flagged, and absolute https:// URLs are fine.

The finding is rated medium. Browsers' default blocking reduces the likelihood of exploitation, but where blocking does not apply, the impact is arbitrary script execution in your origin. The evidence attached to the finding lists each offending URL with the tag and attribute that referenced it, so you can search your templates or content store for the exact string.

The scan only sees what is present in the delivered HTML. Resources added later by JavaScript, or on pages the scanner does not fetch, may still need a manual check in the browser console.

Fixing it

1. Find every reference

Search source and content for the hostnames in the evidence:

grep -rn "http://" templates/ static/ --include="*.html" --include="*.js" --include="*.css"

For CMS-driven sites, also check the database for absolute URLs stored in posts, widgets and theme options. Then open the page in a browser with developer tools. The console reports each blocked or upgraded request with its URL.

2. Change the URLs

Switch to https:// when the host supports it, which nearly all CDNs and widget providers do:

<script src="https://cdn.example.net/vendor/analytics.js"></script>

If a third party only serves cleartext, do not keep it. Self-host the file, pin a version, and consider a Subresource Integrity attribute so any later change is detected:

<script src="/assets/vendor/analytics-4.2.1.js"
        integrity="sha384-REPLACE_WITH_HASH"></script>

3. Update configuration, not just markup

Set the site URL in your CMS or framework to https://. Check any reverse proxy too. If TLS terminates at a load balancer, make sure the application trusts the forwarded protocol header so it generates https:// links instead of http:// ones.

4. Add a safety net

The upgrade-insecure-requests directive tells the browser to rewrite insecure subresource URLs to HTTPS before fetching them:

Content-Security-Policy: upgrade-insecure-requests

For nginx:

add_header Content-Security-Policy "upgrade-insecure-requests" always;

This is a backstop and not a repair. It only works when the target host actually answers on HTTPS, and the cleartext URLs stay in your source. Fix the references, then keep the header to catch regressions. You can roll out a stricter policy in report-only mode first:

Content-Security-Policy-Report-Only: default-src https:; report-uri /csp-report

5. Keep the rest of the transport story intact

The same compliance item also expects cleartext HTTP to redirect straight to HTTPS without an intermediate downgrade, and HSTS to be published with a usable lifetime:

Strict-Transport-Security: max-age=31536000; includeSubDomains

HSTS makes the browser refuse cleartext connections to your host. It does not cover subresources on other hosts, so you still need to fix those references.

Confirming the fix

  1. Reload the affected pages with the developer console open. There should be no mixed-content warnings.
  2. Run curl -s https://example.com/ | grep -Eo '(src|href|data)="http://[^"]+"'. It should return nothing.
  3. Trigger a re-scan. The finding clears when the delivered HTML contains no active subresource with an http scheme. If it persists, the evidence list shows the remaining URLs. They are often in a template that renders only on certain pages, or in a cached copy of the page, so purge CDN and application caches before re-scanning.

Key takeaways

  • Mixed active content means an HTTPS page loads scripts, styles, frames or similar resources over http://, which lets a network attacker run code in your origin.
  • It is rated medium because browsers usually block it, so the common result is broken features. Where blocking does not apply, the impact is full script execution.
  • Fix the references themselves: use https://, self-host with Subresource Integrity if a vendor lacks HTTPS, and correct CMS and proxy settings.
  • Treat upgrade-insecure-requests as a safety net, not the repair.
  • Verify with the browser console, a curl grep, and a fresh scan after purging caches.

Check whether your own domain gets this right. Scanning is free and needs no account.

Scan your domain

All articles