Half the page renders, one stylesheet sits greyed out in the Network panel, and the VPN client still reports a healthy tunnel. All three observations are true at once, because the browser judged a request the page made and the tunnel had no vote in that judgment. What closes the case is a decision rather than a setting: repair the reference, escalate it to whoever owns the host, or drop the dependency. Each of those options has a cheap test, and picking the wrong one burns a support cycle.

Why the tunnel cannot cover a subresource

Mixed content begins with an HTTPS document that asks for a subresource over plain HTTP. Every URL is judged on its own scheme, so the parent document's protection never extends to a child request. Encryption added below the browser changes what travels on the wire, not the http:// the markup asked for.

Current browsers sort these requests into two groups and treat them differently. Scripts, stylesheets, iframes and calls made with fetch, XMLHttpRequest or WebSocket are refused outright, with no upgrade attempt first. Images, audio and video are rewritten to https:// and requested again, and the load is abandoned when that secure fetch fails. A subresource URL whose host is a bare IP address is exempt from upgrading, so an HTTP image on an IP host stays blocked instead of being quietly repaired. The split, including that exemption on the upgradeable side, is documented in Mozilla's mixed content guide. Chrome applies a similar refusal to insecure downloads started from a secure page, which is why a PDF link can die while the surrounding page looks intact.

The greyed-out row is therefore the control working, not evidence that the tunnel leaked plaintext. Treat the row as a finding that points at one reference rather than at the whole page.

Decide who owns the insecure reference

Sort the offending URL by where it is produced before editing anything. That answer decides whether you can ship a fix today, whether a vendor has to release one, or whether the dependency has to leave the page. Read it from the Initiator column in the Network panel, since the markup on screen is often assembled at runtime.

Where the URL comes fromWho can fix itFirst move
Hardcoded in a template or partial you deployYouReplace it with the https:// form, then clear the cache
Injected by a tag manager or a vendor bundleThe vendor, with your ticketSend the exact URL, request type and console line
Served only on port 80 with no TLS listenerThe host ownerAsk for TLS, front it with something you run, or drop it

When the host already answers on 443 and only the reference says http, the repair is local: change the reference, purge the page cache and confirm the row turns https. A host that listens on port 80 alone cannot be edited into compliance, so the resource moves, gets fronted by something you control, or leaves. A URL injected by a tag manager keeps appearing even when your own template is clean, and that case belongs in a ticket with the exact URL and console line attached. Telling staff to allow insecure content is not one of these options, because it switches off the check for every site that browser profile visits.

Repair the reference instead of the browser setting

Reload the failing flow with the network log preserved and filter the panel by the host you suspect. The console names the URL and the directive, which settles whether a request was refused or upgraded before you touch a template.

curl -sSI https://cdn.example.org/vendor.js | head -n 1
curl -sS -o /dev/null -w '%{http_code} %{url_effective}\n' -L https://cdn.example.org/vendor.js

Two supporting controls are worth knowing, and neither replaces the repair. A Content-Security-Policy header carrying upgrade-insecure-requests makes the browser rewrite http subresource URLs before they leave the page, which catches old references you have not found yet. The rewritten request still fails when the target host serves no HTTPS, so the header only changes which URL the browser tries. HSTS works per host, which means a policy on your own domain does nothing for a third-party CDN that never sent the header. After a template edit, purge the page cache and search the rendered HTML for the old hostname, because the same URL can also arrive through a partial, a translation string or a database field.

Follow redirects as well, since a chain that starts at https:// can land on an http:// location and the browser judges the final hop. The -L form of the second command above prints that effective URL for you. If the last hop is plain http, the reference is still wrong even though the link you edited looked fine.

Confirm the page with the console and the network panel

Reload with the cache disabled and walk the flow again, including the buttons that load content on demand. A first page load hides lazy widgets, map tiles and player scripts that only appear after a click. The console should carry no mixed-content entries and every row you touched should show https. Capture the console and the request row before closing the ticket, because that state is hard to reconstruct after the next deploy.

When the resource belongs to someone else, send four things: the exact URL, the request type, the console text and the page where it appears. Redact session identifiers from anything you paste into a ticket. A report that only says images are broken gives the owner nothing to search for.

The tunnel keeps doing its own job while the fix lives in the reference that produced the request. Search the template and the vendor bundle for the hostname once more after the deploy, and close the case only when no blocked mixed-content entry remains in the console.

Artitgels cun il medem tema