/ Redirect Checker Fixes / Mixed Content

How to Fix Mixed Content During Redirect

Mixed content happens when an HTTPS page loads resources over HTTP — images, scripts, stylesheets, fonts. Modern browsers block "active" mixed content (scripts, XHR) entirely and warn or block "passive" mixed content (images, video). The page looks broken to users and loses functionality. This guide covers identifying every offending URL, the modern CSP fix that handles the bulk automatically, and the source-level updates that prevent recurrence. For related fixes, see the Redirect Checker Fixes index.

1. Audit current mixed content

Step 1
DevTools Console
Open any HTTPS page → DevTools → Console tab → reload. Mixed content warnings appear as red errors:
Mixed Content: The page at 'https://...' was loaded over HTTPS,
but requested an insecure script 'http://...'. This request 
has been blocked.
Each warning lists the offending URL.
Step 2
Lighthouse audit
Lighthouse → "Uses HTTPS" audit lists every HTTP resource requested by the page. Direct, actionable list.
Step 3
Server-side grep
# Find HTTP URLs in HTML/CSS/JS files
grep -rn "http://" ./public --include="*.html" --include="*.css" --include="*.js" | \
  grep -v "http-equiv" | \
  grep -v "schema.org" | \
  head -50

# Schema URLs and http-equiv attributes are not actual asset requests — skip those.

2. Categorise the findings

TypeBrowser behaviourExample
ActiveBlocked entirely<script>, <iframe>, XHR/fetch, <link rel="stylesheet">
PassiveWarning, may auto-upgrade<img>, <video>, <audio>
Form submissionBrowser warning, blocked in some<form action="http://...">

3. The CSP upgrade-insecure-requests directive

The quickest broad fix: add this Content-Security-Policy directive. Browsers automatically rewrite http:// resource requests to https:// before sending. No HTML changes needed.

nginx

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

Apache

Header always set Content-Security-Policy "upgrade-insecure-requests"

HTML meta tag fallback

<meta http-equiv="Content-Security-Policy" 
      content="upgrade-insecure-requests">
⚠️ This works for resources where the target server actually supports HTTPS. If you reference http://old-cdn.com/script.js and that server doesn't have HTTPS, the upgrade fails — request still goes to HTTP and gets blocked.

4. Update hardcoded HTTP URLs at source

upgrade-insecure-requests is a safety net. The real fix is updating source content so HTTP URLs don't exist in the first place.

WordPress: database search-replace

# With WP-CLI
wp search-replace 'http://example.com' 'https://example.com' \
  --skip-columns=guid --dry-run

# After confirming output
wp search-replace 'http://example.com' 'https://example.com' \
  --skip-columns=guid

# For external HTTP image references in older content
wp search-replace 'src="http://' 'src="https://' --skip-columns=guid
# Caveat: some external sites may not support HTTPS — check before bulk replace

Static sites: grep + sed

# Find first
grep -rln 'src="http://' ./public --include="*.html"
grep -rln 'href="http://' ./public --include="*.css"

# Replace (test on one file first)
sed -i 's|src="http://example\.com|src="https://example.com|g' file.html

# Bulk for own domain
find ./public -name "*.html" -exec sed -i \
  's|src="http://example\.com|src="https://example.com|g' {} +

Find third-party HTTP URLs

# Identify which external domains are referenced over HTTP
grep -rEh 'http://[a-z0-9.-]+' ./public --include="*.html" --include="*.js" | \
  grep -oE 'http://[a-z0-9.-]+' | \
  sort -u | head -20

# Check each: does the domain support HTTPS now?
for url in $(cat http-urls.txt); do
  https_url="${url/http/https}"
  status=$(curl -s -o /dev/null -w "%{http_code}" "$https_url")
  echo "$status $https_url"
done

5. Common offenders

Old analytics snippets

<!-- Old Google Analytics -->
<script src="http://www.google-analytics.com/ga.js"></script>

<!-- Current GA4 -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXX"></script>

Old jQuery / library CDNs

<!-- Old -->
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>

<!-- New -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>

WordPress widgets with hardcoded URLs

// Custom HTML widgets, sidebar widgets often have hardcoded HTTP URLs
// Search and update via WP admin or database search-replace

User-submitted content (comments, profiles)

// Sanitise on input: strip http: from img/script tags
function sanitiseUserHTML($html) {
  return preg_replace(
    '|(<(img|script|iframe|link)[^>]*\bsrc=["\'])http://|i',
    '$1https://',
    $html
  );
}

6. Forms posting to HTTP

<!-- WRONG: HTTPS page → form POST over HTTP -->
<form action="http://example.com/submit" method="post">
  <input type="email" name="email">
</form>

<!-- RIGHT -->
<form action="https://example.com/submit" method="post">
  <input type="email" name="email">
</form>

Modern browsers warn before submitting forms to HTTP. Some block entirely. Always use HTTPS in form action URLs.

7. Verify resolution

Step 1
DevTools Console clean
Reload page in incognito. Console shows zero "Mixed Content" warnings. Network tab shows all resources as HTTPS.
Step 2
Browser address bar
Chrome shows green/grey padlock for HTTPS. With mixed content, padlock shows warning triangle or "Not Secure". Clean fix returns the padlock to default.
Step 3
Lighthouse re-audit
"Uses HTTPS" audit should pass. All resource lists clear.

8. Prevent regression

# Lint rule: block http:// in templates and content
# .eslintrc — for JS frameworks
{
  "rules": {
    "no-restricted-syntax": [
      "error",
      {
        "selector": "Literal[value=/^http:\\/\\//]",
        "message": "Use https:// instead of http://"
      }
    ]
  }
}

# Pre-commit hook
git diff --cached | grep -nE '^\+.*http://' && {
  echo "ERROR: http:// found in staged changes"
  exit 1
}
💡 Add upgrade-insecure-requests CSP as the safety net first — it catches stragglers without breaking the page. Then work through grep results to fix at source. Eventually you can remove the CSP directive if confident no http:// URLs remain, but it's cheap to leave in place as defence-in-depth.

↪️ Re-run the Redirect Checker

Verify mixed-content findings clear.

Run Redirect Checker →
Related Guides: Redirect Checker Fixes  ·  Fix HTTPS Redirects  ·  Security Audit Fixes  ·  Redirect Checker Guide
💬 Got a problem?