PL-034mediumLive posture

Page loads scripts or styles over plain HTTP

Your HTTPS page pulls a script or stylesheet from an http:// address, which anyone on the network can replace.

Severity
Medium
Who can exploit it
Anyone on the visitor’s network
Found by
PatchLabs Live posture: the HTML of your home page
Lab proof
Not lab-proven: read from your home page’s HTML

What it is

Mixed content is an HTTPS page that loads part of itself over plain http://. PL-034 covers the parts that can take over the page: <script src="http://…"> and stylesheets (<link rel="stylesheet" href="http://…">). Whoever controls the network can replace that file, and a replaced script runs with full access to your page, including the signed-in session.

Modern browsers block these loads outright, so in practice the usual symptom is a broken feature: a widget, a font or an analytics tag that silently never loads, with a “Mixed Content” error in the console.

Why AI builders produce it

An old embed snippet copied from a provider’s documentation, a CDN URL written with http://, or a template from years ago. A generator pastes what it was given, and local development over http://localhost raises no error.

What we see

A synthetic example for app.example.com, shortened. Not taken from any real site.

index.html (vulnerable, synthetic)
<!-- index.html (vulnerable) -->
<link rel="stylesheet" href="http://cdn.example.net/widget/1.4/widget.css">
<script src="http://cdn.example.net/widget/1.4/widget.js"></script>

Check it yourself

check-pl-034.sh
# script and stylesheet URLs that start with http://
curl -s https://your-app.com | grep -oiE '<(script|link)[^>]+(src|href)="http://[^"]+"'

Scripts your bundle adds at runtime don’t appear in the HTML. Open the site in the browser with DevTools → Console: every blocked load is listed as “Mixed Content” with its URL.

The fix

Change each URL to https://; nearly every provider serves the same file over HTTPS. Better still, install the library from npm so it ships inside your own bundle. Then add upgrade-insecure-requests as a safety net: it tells the browser to fetch any leftover http:// subresource over HTTPS instead.

In your code

index.html (fixed, synthetic)
<!-- index.html (fixed) -->
<link rel="stylesheet" href="https://cdn.example.net/widget/1.4/widget.css">
<script src="https://cdn.example.net/widget/1.4/widget.js"></script>

Vercel

vercel.json
{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "Content-Security-Policy", "value": "upgrade-insecure-requests" }
      ]
    }
  ]
}

If you already send a Content-Security-Policy (PL-030), add upgrade-insecure-requests to it instead of adding a second header.

Netlify / Cloudflare Pages

public/_headers
# public/_headers  (Vite copies public/ into the publish folder)
/*
  Content-Security-Policy: upgrade-insecure-requests

The file must end up in your publish directory (dist for Vite). Bolt projects deployed to Netlify use this file too. The same rule can live in netlify.toml under [[headers]] if you prefer one config file.

Lovable

This one works as a meta tag in index.html, so it needs nothing from the host:

index.html
<!-- index.html, inside <head> -->
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

Live posture findings come with the header or setting to change. PatchLabs never changes your hosting or your repo.

How PatchLabs finds it

live posture · report excerpt
[LOAD]    https://app.example.com/ → 200
          <script src="http://cdn…">    FLAG
          1 script, 1 stylesheet
synthetic exampleLive posture · read from the home page’s response

Live posture reads the HTML of your home page from its one page load and lists <script> and stylesheet URLs that start with http://. It doesn’t download those files, run the page’s JavaScript or look at other pages, so scripts your app adds later are not seen: the console check above covers them.

When the pattern is intended

Never for scripts or styles on an HTTPS page. Plain-HTTP images are a smaller problem and are not part of this finding, but fix them while you are there.

Why it’s rated medium

Medium: a replaced script is a full takeover of the page, but it needs someone on the network path, and current browsers block most of these loads anyway. 15 points in the Live posture grade.

Guides

Free check

Does your site have PL-034?

Type your site’s address. The free headers check loads your public home page once, like any visitor, and grades HTTPS, the certificate, security headers, cookie flags and mixed content. No sign-up, and the result isn’t stored.

Free, no sign-upLoads your public home page onlyHow Live posture works

Last reviewed 10 Nov 2026. Finding IDs are stable: link to them freely. Spotted a mistake? Tell us.