VibeSecurity

Fix

Fix: Mixed Content: page loaded over HTTPS, insecure resource

Your page is served over HTTPS, but it asked for a script, API call, image or frame over plain http://. Browsers block or upgrade those requests because an insecure resource can be read or changed in transit.

By the VibeSecurity team3 min read

What this means

Chrome prints: Mixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure resource 'http://...'. This request has been blocked; the content must be served over HTTPS. Browsers split mixed content into two groups. Images, audio and video are upgradable, so the browser retries them over HTTPS. Everything else, including scripts, stylesheets, iframes and fetch calls, is blockable and is simply not loaded.

Why it happens

  • An API base URL is set to http:// in an environment variable. It worked on localhost, which browsers treat as secure, and broke on the deployed HTTPS site.
  • The backend runs on a raw server IP and port with no TLS certificate, a common result of deploying a generated backend by hand.
  • Hard-coded http:// links to images, fonts or scripts in generated code or copied snippets.
  • Stored content, such as user uploads or CMS entries, contains absolute http:// URLs.
  • A WebSocket uses ws:// instead of wss://.

How to fix it

  1. 1Open the console and list each blocked URL. The message names it.
  2. 2Search your code and environment variables for http:// and ws://. Change each to https:// or wss:// and check the resource actually loads over HTTPS.
  3. 3If your own API has no HTTPS, put it behind a host or proxy that provides a certificate, and give it a domain name. Do not ship a production API on a bare IP over http.
  4. 4If a third party offers no HTTPS, fetch it from your server and pass the result to the browser over your own HTTPS route, or replace the provider.
  5. 5Fix stored URLs in your database with a one-off update.
  6. 6Add the upgrade-insecure-requests CSP directive as a safety net for links you missed. It only helps when the target also serves HTTPS.
Find insecure URLs, fix the variable, add a safety net
grep -rnE "(http|ws)://" src .env* --include='*' | grep -v localhost

NEXT_PUBLIC_API_URL=https://api.yourapp.com

Content-Security-Policy: upgrade-insecure-requests

How to confirm the fix

  • Load each main page of your live site with the console open. There should be no Mixed Content messages.
  • In the Network tab, add the Scheme column or filter by mixed-content:all in Chrome. Every request should be https or wss.
  • Check the API URL your deployed bundle uses. In the Network tab, click an API request and confirm the full URL begins with https://.
  • Run curl -I https://api.yourapp.com/health against your own API to confirm it answers over HTTPS with a valid certificate. curl fails loudly if the certificate is wrong.

Frequently asked questions

Why did it work on localhost?

Browsers treat http://localhost as a secure context, and a local page served over http has no HTTPS to mix with. The problem appears once the page itself is on HTTPS.

Does upgrade-insecure-requests fix everything?

No. It rewrites http:// requests to https:// before they are sent. If the other server does not support HTTPS, the request fails instead of being blocked.

Images show a warning but still load. Do I need to fix them?

Yes. Browsers upgrade images to HTTPS automatically, and if the upgraded request fails the image will not load. Use https:// URLs so the result is predictable.

Sources

  1. 1.MDN: Mixed content
  2. 2.W3C: Mixed Content specification
  3. 3.MDN: CSP upgrade-insecure-requests
  4. 4.MDN: Strict-Transport-Security