HSTS and mixed content get lumped together because they both live in the HTTPS world. But they solve different problems, fail in different ways, and trip up different teams.
If you’re building or maintaining a site, you need to understand the gap between them:
- HSTS tells the browser to always use HTTPS for your domain.
- Mixed content happens when an HTTPS page still loads some resources over HTTP.
That distinction matters. I’ve seen teams proudly enable HSTS and assume they’re done, while their pages still pull images, scripts, or CSS over plain HTTP. That’s not “mostly secure.” That’s a site with sharp edges.
The short version
HSTS
A response header that instructs browsers to rewrite future HTTP requests to HTTPS.
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Mixed content
A browser security issue triggered when an HTTPS page loads insecure subresources.
<!-- Bad -->
<script src="http://cdn.example.com/app.js"></script>
<img src="http://example.com/logo.png" alt="Logo">
<link rel="stylesheet" href="http://example.com/styles.css">
These are related, but not interchangeable.
What HSTS actually gives you
HSTS stands for HTTP Strict Transport Security. It’s a browser-enforced rule: once the browser sees the header on a secure response, it remembers that your domain must only be contacted over HTTPS for the duration of max-age.
A typical production header looks like this:
Strict-Transport-Security: max-age=31536000; includeSubDomains
If you want preload eligibility:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Pros of HSTS
1. It kills protocol downgrade attacks
Without HSTS, a user typing example.com may start on HTTP and then get redirected to HTTPS. That first hop is a weak point. HSTS removes that after the browser learns the policy.
2. It protects users from sloppy links
Users, bookmarks, old docs, and third-party links still point to http:// more often than people admit. HSTS helps clean that up automatically in the browser.
3. It reduces accidental insecure access
Developers and ops teams make mistakes. HSTS gives you a safety net at the browser layer.
4. It works well at scale
Once enabled correctly, it’s low maintenance. Set the header at your edge or app server and keep it consistent.
Cons of HSTS
1. It does not fix mixed content
This is the big misunderstanding. HSTS upgrades navigation to your domain. It does not magically sanitize every insecure resource reference in your HTML, CSS, or JS.
2. Bad rollout can break subdomains
If you use includeSubDomains, every subdomain must support HTTPS correctly. That includes weird legacy hosts nobody has touched in five years.
3. Preload is hard to undo
If you submit your domain to browser preload lists, rollback is slow and painful. Don’t preload unless you’re sure your house is in order.
4. First visit is still special unless preloaded
Normal HSTS only starts after the browser receives the header once over HTTPS. Until then, the first connection can still be exposed to downgrade attacks. Preload helps, but comes with that operational commitment.
What mixed content actually breaks
Mixed content means an HTTPS page requests some resources over HTTP. Browsers hate this for good reason: an attacker on the network can tamper with those insecure resources even if the page itself loaded over TLS.
Example:
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="http://static.example.com/site.css">
</head>
<body>
<img src="http://images.example.com/banner.jpg" alt="Banner">
<script src="http://cdn.example.com/app.js"></script>
</body>
</html>
That page is not fully trustworthy. The browser may block some of it, auto-upgrade some of it, or show warnings depending on the resource type and browser behavior.
Pros of mixed content handling in browsers
This is a weird category because mixed content itself is bad. But browser enforcement around it does help.
1. Browsers block dangerous resource types
Scripts, stylesheets, iframes, and XHR/fetch requests over HTTP are generally blocked on HTTPS pages. That prevents some truly ugly attacks.
2. Warnings expose insecure dependencies
Mixed content errors often reveal forgotten legacy assets, bad CMS templates, or old third-party integrations.
3. Auto-upgrade helps with some passive resources
Modern browsers may upgrade image/audio/video requests from HTTP to HTTPS when possible. Nice when it works, but I would never rely on it as a strategy.
Cons of mixed content
1. It breaks pages in production
Blocked scripts and CSS don’t fail gracefully. They break layouts, interactions, analytics, payment flows, everything.
2. It creates false confidence
The page has a padlock, so people assume it’s secure. Meanwhile, some image or script source is still plain HTTP.
3. Third-party assets are often the real problem
Your own code may be clean, but some ad tag, widget, font loader, or old marketing snippet drags in HTTP.
4. It gets buried in templates and generated content
Mixed content is often hidden in CMS fields, Markdown content, WYSIWYG editors, email templates, or JavaScript-generated URLs.
HSTS vs mixed content: side-by-side
Here’s the cleanest way to compare them.
| Topic | HSTS | Mixed Content |
|---|---|---|
| What it is | Security response header | Browser security issue |
| Main goal | Force HTTPS for future requests | Prevent insecure resources on HTTPS pages |
| Controlled by | Server response header | HTML, CSS, JS, third-party resources |
| Fix type | Header/config change | Code/content/dependency cleanup |
| Can it break pages? | Yes, if HTTPS isn’t ready everywhere | Yes, blocked resources break rendering/functionality |
| Solves downgrade risk? | Yes | No |
| Solves insecure subresource loads? | No | Detection/enforcement only |
That last row is the one developers should remember.
Real-world example: why HSTS doesn’t save a mixed page
Say your server sends:
Strict-Transport-Security: max-age=31536000; includeSubDomains
And your page contains:
<script src="http://assets.example.com/main.js"></script>
What happens?
- The browser knows
example.comshould use HTTPS. - The page itself loads over HTTPS.
- The script request is still explicitly
http://assets.example.com/main.js. - Depending on browser behavior and host setup, that script is blocked or upgraded.
- If it’s blocked, your app breaks.
- If
assets.example.comdoesn’t support HTTPS correctly, upgrade won’t help anyway.
So yes, HSTS improves transport security. No, it doesn’t excuse bad resource URLs.
Best use cases for HSTS
HSTS is a strong fit when:
- your entire site and subdomains are HTTPS-ready
- you want to eliminate protocol downgrade risk
- you control your DNS and TLS setup well
- you can safely commit to long-lived HTTPS-only behavior
A simple Nginx example:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Apache:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Express behind HTTPS termination:
app.use((req, res, next) => {
res.setHeader(
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains"
);
next();
});
Start with a shorter max-age if you’re nervous:
Strict-Transport-Security: max-age=300
Then ramp up after validation.
Best use cases for mixed content cleanup
Mixed content work is less glamorous, but it’s usually where the real effort is.
You should prioritize cleanup when:
- you recently migrated from HTTP to HTTPS
- you use a CMS with old embedded content
- you load third-party scripts, fonts, images, or iframes
- browser consoles show blocked resource errors
- pages partly work over HTTPS but feel flaky
Typical fixes:
1. Use relative or HTTPS URLs
Prefer explicit HTTPS for external resources.
<script src="https://cdn.example.com/app.js"></script>
2. Stop hardcoding http://
Search templates, content blobs, and JS for insecure URLs.
3. Add CSP upgrade support where it makes sense
This can help as a migration aid, not as a permanent excuse.
Content-Security-Policy: upgrade-insecure-requests
That tells the browser to rewrite insecure resource URLs to HTTPS. Useful during cleanup, but if the target host doesn’t serve HTTPS correctly, things still fail.
4. Audit third-party dependencies
If a vendor still requires HTTP in 2026, I’d seriously question why they’re on the page at all.
Which is more important?
That’s the wrong question. You need both.
If I had to prioritize rollout order for a messy legacy site, I’d usually do this:
- Get HTTPS working everywhere
- Fix mixed content
- Enable HSTS with a safe max-age
- Increase max-age
- Consider
includeSubDomainsand preload only after full validation
Why this order? Because HSTS locks in HTTPS expectations, while mixed content cleanup makes the actual page secure and functional. Shipping HSTS onto a half-migrated stack is how you create outages and angry Slack threads.
How to test both
Check headers and page behavior separately.
For HSTS, verify the response header is present on HTTPS responses and configured as intended. For mixed content, inspect browser console errors, network requests, and rendered page behavior.
If you want a quick sanity check on your header setup, run a free scan with HeaderTest. It’s a fast way to catch missing or weak security headers before you start arguing about preload.
My practical take
HSTS is a strong, boring, high-value control. I like boring controls. They save you from common mistakes and quietly reduce risk.
Mixed content is where migrations get exposed. It’s less about policy and more about code quality, asset hygiene, and whether anyone actually audited the long tail of the site.
So the honest comparison is this:
- HSTS is a seatbelt
- Mixed content is whether the car still has holes in the floor
Use the seatbelt. Fix the holes too.