Insecure API Calls (HTTP)
Sending a postcard instead of a sealed letter — that's what HTTP API calls do. Anyone between you and the server can read everything.
What is this?
You need to send your bank account details to someone. Do you write them on a postcard (visible to every mail carrier, sorting machine, and nosy neighbor) or put them in a sealed envelope? Making API calls over HTTP instead of HTTPS is the postcard approach. Every piece of data — passwords, personal information, API responses — travels across the internet in plain text. Anyone on the same network (coffee shop Wi-Fi, hotel network, compromised router) can intercept, read, and modify it.
Why it matters
- For your visitors: When your page makes HTTP requests, anyone on the network path can see the data being sent and received. This includes login credentials, personal information, form submissions, and any data your API returns. On public Wi-Fi, this is trivially easy to exploit with freely available tools. Your visitors' data is exposed without them knowing.
- For your business: Modern browsers actively warn users about insecure connections, mark HTTP pages as "Not Secure" in the address bar, and block mixed content (HTTP requests from HTTPS pages). Google ranks HTTPS sites higher than HTTP. Beyond SEO, an intercepted API call can lead to data breaches, session hijacking, and man-in-the-middle attacks where an attacker modifies the data in transit.
- The standard: All API calls should use HTTPS. All pages should be served over HTTPS. HTTP should redirect to HTTPS. Mixed content (HTTP resources on an HTTPS page) should be eliminated entirely. Free TLS certificates from Let's Encrypt make this a zero-cost requirement.
// All requests over HTTPS — encrypted in transit
const response = await fetch("https://api.example.com/user/profile", {
headers: { Authorization: `Bearer ${token}` },
});// HTTP: data sent in plain text — anyone can intercept
const response = await fetch("http://api.example.com/user/profile", {
headers: { Authorization: `Bearer ${token}` },
});
// Your auth token just traveled across the internet unencryptedHow to fix it
React / Next.js
Ensure all API endpoints use HTTPS and add a Content Security Policy to prevent mixed content.
// Make sure all your API URLs use https://
const API_BASE = "https://api.yoursite.com";
async function fetchUserProfile(token: string) {
const res = await fetch(`${API_BASE}/user/profile`, {
headers: { Authorization: `Bearer ${token}` },
});
return res.json();
}Add security headers in your Next.js config to enforce HTTPS:
// next.config.ts
const nextConfig = {
async headers() {
return [
{
source: "/(.*)",
headers: [
// Force HTTPS for all future visits
{
key: "Strict-Transport-Security",
value: "max-age=31536000; includeSubDomains; preload",
},
// Block mixed content
{
key: "Content-Security-Policy",
value: "upgrade-insecure-requests",
},
],
},
];
},
};
export default nextConfig;Use a proxy for third-party APIs that do not support HTTPS (rare but possible):
// src/app/api/proxy/route.ts
// If a legacy API only supports HTTP, proxy it through your HTTPS server
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const query = searchParams.get("q");
// Your server makes the HTTP call — the visitor's browser never does
const res = await fetch(`http://legacy-api.internal/search?q=${query}`);
const data = await res.json();
return Response.json(data);
}Plain HTML
Ensure your site and all resources use HTTPS.
<!-- Force HTTPS redirect (server config) -->
<!-- nginx -->
<!--
server {
listen 80;
server_name yoursite.com;
return 301 https://$host$request_uri;
}
-->
<!-- Add meta tag to upgrade insecure requests -->
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />
<!-- All resource URLs should use https:// -->
<script src="https://cdn.example.com/lib.js"></script>
<link rel="stylesheet" href="https://cdn.example.com/styles.css" />
<img src="https://cdn.example.com/image.jpg" alt="Photo" />
<!-- Or use protocol-relative URLs (they inherit the page's protocol) -->
<!-- Note: explicit https:// is preferred over protocol-relative -->Check for and fix mixed content — HTTP resources loaded on an HTTPS page:
<!-- BAD: mixed content — HTTP image on HTTPS page -->
<img src="http://example.com/photo.jpg" alt="Photo" />
<!-- GOOD: everything over HTTPS -->
<img src="https://example.com/photo.jpg" alt="Photo" />Quick HTTPS checklist:
- Get a free TLS certificate from Let's Encrypt
- Redirect all HTTP traffic to HTTPS
- Update all hardcoded
http://URLs tohttps:// - Add
Strict-Transport-Securityheader - Add
upgrade-insecure-requestsCSP directive - Test with browser DevTools Console for mixed content warnings
HTTPS is the absolute minimum security requirement in 2026. The cat will not even look at an HTTP site with any semblance of approval. Encrypt everything.
How the cat scores this
The scanner checks all network requests made by the page for HTTP (non-HTTPS) URLs. This includes API calls, image sources, script sources, stylesheet links, and iframe sources. Each HTTP request on an HTTPS page is flagged as mixed content. The scanner also checks for the Strict-Transport-Security header and upgrade-insecure-requests CSP directive. Pages served entirely over HTTP (not just mixed content) receive the most severe penalty.
Further reading
- web.dev: Why HTTPS matters — Google's case for universal HTTPS
- Let's Encrypt — free, automated TLS certificates
- MDN: Strict-Transport-Security — HSTS header reference