{"id":15704,"date":"2026-09-06T01:12:16","date_gmt":"2026-09-05T23:12:16","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/toolbox\/third-party-origin-integrity-checker\/"},"modified":"2026-09-06T01:12:16","modified_gmt":"2026-09-05T23:12:16","slug":"third-party-origin-integrity-checker","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/third-party-origin-integrity-checker\/","title":{"rendered":"Third-Party Origin &#038; Subresource Integrity Checker: who a page loads from, and what it trusts"},"content":{"rendered":"<div class=\"gtm-analyser-container\" style=\"background: var(--bg-panel, #1e1e24); padding: 25px; border-radius: 8px; border: 1px solid var(--border, #2a2a35);\">\n<p style=\"color: var(--text-secondary, #a0a0b0); margin-bottom: 20px;\">A page is rarely a single file. Scripts, stylesheets, images and frames come from somewhere, and each origin is a party that sees the visitor&#039;s IP address, one more connection to open, and \u2014 for scripts and stylesheets \u2014 code that runs with all the rights of the page. This check reads the markup once and sorts what it finds by origin, protocol and integrity.<\/p>\n<div style=\"margin-bottom: 14px;\">\n        <label for=\"herkunft-url\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Page address<\/label><br \/>\n        <input id=\"herkunft-url\" type=\"text\" value=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; box-sizing: border-box; font-family: monospace;\">\n    <\/div>\n<p style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.82rem; margin-bottom: 16px;\">From this server: exactly one request for the page, capped at 1.5 MB. None of the subresources are fetched. No cookies are sent, no scripts are executed, nothing is stored beyond the rate counter.<\/p>\n<p>    <button id=\"herkunft-btn\" class=\"button\" style=\"background: var(--accent, #7ee787); color: var(--on-accent, #0b1114); border: none; padding: 12px 24px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Check origins<\/button><\/p>\n<div id=\"herkunft-ausgabe\" style=\"margin-top: 22px;\"><\/div>\n<p style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.8rem; margin: 24px 0 0;\">Limits worth knowing: only what stands in the served HTML is seen. What a script loads at runtime \u2014 the usual case for tag managers and consent tools \u2014 stays invisible, and so does anything inside a frame. Two hosts count as the same party when their registrable name matches, so a CDN subdomain of the same domain is not counted as third party.<\/p>\n<\/div>\n<p><script>\n(function () {\n    'use strict';<\/p>\n<p>    const T = {\"einleitung\":\"A page is rarely a single file. Scripts, stylesheets, images and frames come from somewhere, and each origin is a party that sees the visitor\\u0027s IP address, one more connection to open, and \u2014 for scripts and stylesheets \u2014 code that runs with all the rights of the page. This check reads the markup once and sorts what it finds by origin, protocol and integrity.\",\"label_url\":\"Page address\",\"datenschutz\":\"From this server: exactly one request for the page, capped at 1.5 MB. None of the subresources are fetched. No cookies are sent, no scripts are executed, nothing is stored beyond the rate counter.\",\"knopf\":\"Check origins\",\"laeuft\":\"Fetching page...\",\"grenze\":\"Limits worth knowing: only what stands in the served HTML is seen. What a script loads at runtime \u2014 the usual case for tag managers and consent tools \u2014 stays invisible, and so does anything inside a frame. Two hosts count as the same party when their registrable name matches, so a CDN subdomain of the same domain is not counted as third party.\",\"h_fremde\":\"Third-party origins\",\"tabelle_hinweis\":\"Active means a script or stylesheet: content that can run code or change how the page looks. Those are the ones that need integrity, and the ones browsers block outright over http.\",\"h_befunde\":\"Findings\",\"sp_host\":\"Host\",\"sp_anzahl\":\"References\",\"sp_aktiv\":\"Active\",\"sp_preconnect\":\"preconnect\",\"art_skript\":\"scripts\",\"art_blatt\":\"stylesheets\",\"art_bild\":\"images\",\"art_rahmen\":\"frames\",\"art_medium\":\"media\",\"zeile_seite\":\"Page\",\"zeile_teile\":\"Subresources in markup\",\"zeile_nach_art\":\"By kind\",\"zeile_fremde\":\"Third-party origins\",\"zeile_dauer\":\"Took\",\"zeile_limit\":\"Checks left this hour\",\"wert_ja\":\"yes\",\"wert_nein\":\"no\",\"stufe_hoch\":\"High\",\"stufe_mittel\":\"Medium\",\"stufe_niedrig\":\"Low\",\"stufe_info\":\"Information\",\"stufe_gut\":\"In order\",\"keine_befunde\":\"Nothing to report.\",\"urteil_gut\":\"The page loads from where it should.\",\"urteil_warnung\":\"The page works, but it trusts more than it needs to.\",\"urteil_kritisch\":\"Content that can run code travels over http, or the page itself is not encrypted.\",\"fehler_kein_token\":\"The check could not be started because reCAPTCHA did not load.\",\"fehler_captcha\":\"reCAPTCHA classified the request as automated. Reloading the page normally helps.\",\"fehler_zu_viele\":\"The limit of {limit} checks per hour for this address has been reached.\",\"fehler_adresse\":\"That address cannot be used.\",\"fehler_abruf\":\"The page could not be fetched.\",\"fehler_zaehler\":\"The rate counter is unavailable, so nothing was checked.\",\"fehler_pruefdienst\":\"The reCAPTCHA service could not be reached.\",\"fehler_aufbau\":\"The service is not configured correctly. The fault is on this side.\",\"fehler_eingabe\":\"The request could not be read.\",\"fehler_methode\":\"Wrong request method.\",\"fehler_netz\":\"The service could not be reached.\",\"fehler_antwort\":\"The answer could not be read.\",\"fehler_unbekannt\":\"Something went wrong that has no message of its own.\",\"grund_leer\":\"Nothing was entered.\",\"grund_zu_lang\":\"The input is too long.\",\"grund_unlesbar\":\"It does not parse as an address.\",\"grund_schema\":\"Only http and https addresses are checked.\",\"grund_benutzerinfo\":\"Inputs with credentials in them are refused.\",\"grund_kein_punkt\":\"The host name needs at least one dot.\",\"grund_hostform\":\"A host name is expected, not an IP address.\",\"grund_port\":\"Only the ports 80, 443, 8080 and 8443 are checked.\",\"grund_gesperrter_bereich\":\"That host resolves into a private or reserved network. Those are never fetched.\",\"grund_kein_dns\":\"The host name does not resolve.\",\"grund_abruf\":\"The address did not answer.\",\"grund_zu_viele_spruenge\":\"The address redirects too often.\",\"befund_status\":\"The page answered with status {status} || Subresources were still read from whatever body came back, but a page that does not answer with 200 rarely shows what visitors see.\",\"befund_seite_gekappt\":\"The page is larger than 1.5 MB || It was read up to that point. References beyond it were not seen.\",\"befund_keine_teile\":\"No subresources in the served HTML || Either the page really is a single file, or everything is loaded by script after the fact. This check only sees the markup.\",\"befund_gemischt_aktiv\":\"A {art} loads over http on an https page || {url}. Browsers block this outright: the file never arrives, and the page runs without it. Nothing about it is subtle \u2014 it is the class of mixed content that breaks pages rather than weakening them.\",\"befund_gemischt_passiv\":\"{n} passive subresources load over http || Images and media are not blocked outright, but browsers mark the page as no longer fully secure and may refuse to upgrade. Every one of them can be read and altered on the way.\",\"befund_gemischt_passiv_aufgewertet\":\"{n} passive subresources are written as http, but the CSP upgrades them || upgrade-insecure-requests turns them into https before the request goes out. The markup is untidy, the delivery is not.\",\"befund_aufwertung_rettet\":\"The CSP carries upgrade-insecure-requests || That rewrites http references to https before the request. It rescues the delivery; it does not fix the markup, and a browser without CSP support sees the original.\",\"befund_kein_gemischter_inhalt\":\"Everything is loaded over https || No mixed content \u2014 neither the kind browsers block nor the kind they merely flag.\",\"befund_seite_ohne_https\":\"The page itself is served over http || Everything on it travels unencrypted and can be read or changed on the way. Mixed content is not even a question here, because nothing is mixed: none of it is protected.\",\"befund_protokollrelativ\":\"{n} references start with \\\/\\\/ instead of a protocol || That was the way to write it when sites still answered on both. On an https page it works, but it also means the reference follows whatever the page happens to use.\",\"befund_ohne_integrity\":\"A third-party {art} runs without integrity || {url} from {host}. The file is loaded and executed with all the rights of the page. An integrity attribute pins its hash, so a changed file simply does not run \u2014 which is the difference between a compromised CDN and a compromised site.\",\"befund_mit_integrity\":\"{n} third-party resources carry integrity || Their hash is pinned, so a changed file is refused rather than executed.\",\"befund_keine_fremden_aktiven\":\"No third party runs code on this page || Scripts and stylesheets all come from the page\\u0027s own name. That is one whole class of supply chain risk that does not apply here.\",\"befund_fremde_ursprunge\":\"{n} third-party origin(s) || {liste}. Each one is a DNS lookup, a connection and a party that sees the visitor\\u0027s IP address before anything is agreed.\",\"befund_fremd_ohne_preconnect\":\"No preconnect for {host} || {n} active resources come from there. The connection is only opened once the parser reaches the reference; a preconnect in the head starts it earlier.\",\"befund_alles_eigen\":\"All {n} subresources come from the page\\u0027s own name || No third party is involved, and every connection is already open.\"};<\/p>\n<p>    var ENDPUNKT = '\/lw-herkunftcheck.php';\n    var SITEKEY = '6LcrPkEtAAAAAPo1QCOf-IIM2fCL0UfdJz4y2iSY';\n    var STUFEN = ['hoch', 'mittel', 'niedrig', 'info', 'gut'];\n    var ARTEN = ['skript', 'blatt', 'bild', 'rahmen', 'medium'];<\/p>\n<p>    function liste(w) { return Array.isArray(w) ? w : []; }\n    function zahl(w) { return (typeof w === 'number' && isFinite(w)) ? w : null; }\n    function text(schluessel, daten) {\n        var t = T[schluessel];\n        if (typeof t !== 'string') { return null; }\n        return t.replace(\/\\{([a-z_0-9]+)\\}\/g, function (m, k) {\n            var w = (daten && daten[k] !== undefined && daten[k] !== null) ? daten[k] : null;\n            if (w === null) { return m; }\n            if (k === 'art' && T['art_' + w]) { return T['art_' + w]; }\n            return String(w);\n        });\n    }\n    function kurz(url) {\n        var s = String(url || '').replace(\/^https?:\\\/\\\/\/, '');\n        return s.length <= 52 ? s : s.slice(0, 24) + '\u2026' + s.slice(-26);\n    }\n\n    function bewerten(antwort) {\n        var a = antwort || {};\n        if (a.fehler) { return { fehler: String(a.fehler), grund: a.grund || null, limit: zahl(a.limit) }; }\n        var befunde = liste(a.befunde).map(function (f) {\n            return { key: String(f.key || ''), stufe: STUFEN.indexOf(f.stufe) === -1 ? 'info' : f.stufe, daten: (f.daten &#038;&#038; typeof f.daten === 'object') ? f.daten : {} };\n        });\n        var gruppen = {};\n        STUFEN.forEach(function (s) { gruppen[s] = befunde.filter(function (f) { return f.stufe === s; }); });\n        var fremde = liste(a.fremde).map(function (z) {\n            return { host: String(z.host || ''), anzahl: zahl(z.anzahl), aktiv: zahl(z.aktiv), preconnect: z.preconnect === true };\n        });\n        var nachArt = {};\n        if (a.nach_art &#038;&#038; typeof a.nach_art === 'object') {\n            Object.keys(a.nach_art).forEach(function (k) { if (typeof a.nach_art[k] === 'number') { nachArt[k] = a.nach_art[k]; } });\n        }\n        return {\n            fehler: null, url: String(a.url || ''), endurl: String(a.endurl || ''), host: String(a.host || ''),\n            urteil: (a.urteil === 'gut' || a.urteil === 'warnung' || a.urteil === 'kritisch') ? a.urteil : 'kritisch',\n            teile: zahl(a.teile), nachArt: nachArt, fremde: fremde,\n            befunde: befunde, gruppen: gruppen, dauer: zahl(a.dauer_ms), limitRest: zahl(a.limit_rest)\n        };\n    }\n\n    function skriptLaden() {\n        return new Promise(function (auf) {\n            if (window.grecaptcha) { auf(true); return; }\n            var s = document.createElement('script');\n            s.src = 'https:\/\/www.google.com\/recaptcha\/api.js?render=' + SITEKEY;\n            s.onload = function () { auf(true); }; s.onerror = function () { auf(false); };\n            document.head.appendChild(s);\n            setTimeout(function () { auf(!!window.grecaptcha); }, 8000);\n        });\n    }\n    function tokenHolen() {\n        return skriptLaden().then(function (da) {\n            if (!da || !window.grecaptcha || !window.grecaptcha.ready) { return null; }\n            return new Promise(function (auf) {\n                var fertig = false;\n                function einmal(w) { if (!fertig) { fertig = true; auf(w); } }\n                setTimeout(function () { einmal(null); }, 12000);\n                try {\n                    window.grecaptcha.ready(function () {\n                        if (fertig) { return; }\n                        if (!window.grecaptcha.execute) { einmal(null); return; }\n                        window.grecaptcha.execute(SITEKEY, { action: 'herkunftcheck' }).then(function (t) { einmal(t || null); }, function () { einmal(null); });\n                    });\n                } catch (e) { einmal(null); }\n            });\n        }, function () { return null; });\n    }\n    function abfragen(url) {\n        return tokenHolen().then(function (token) {\n            return fetch(ENDPUNKT, { method: 'POST', headers: { 'Content-Type': 'application\/json' }, body: JSON.stringify({ url: url, token: token || '' }) })\n                .then(function (r) { return r.json().then(function (j) { return j; }, function () { return { fehler: 'antwort' }; }); }, function () { return { fehler: 'netz' }; });\n        });\n    }\n\n    window.LW_TEST = window.LW_TEST || {};\n    window.LW_TEST.HERKUNFT = { bewerten: bewerten, darstellen: null, text: text, kurz: kurz, ENDPUNKT: ENDPUNKT, STUFEN: STUFEN, T: T };\n\n    var btn = document.getElementById('herkunft-btn');\n    var out = document.getElementById('herkunft-ausgabe');\n    if (!btn || !out) { return; }\n\n    function el(tag, stil, txt) { var e = document.createElement(tag); if (stil) { e.setAttribute('style', stil); } if (txt !== undefined &#038;&#038; txt !== null) { e.textContent = txt; } return e; }\n    function wert(id) { var e = document.getElementById(id); return e ? e.value : ''; }\n    var UEBERSCHRIFT = 'font-family: \"Nunito Sans\", sans-serif; font-weight: 700; color: var(--text-primary, #e8e8ee); font-size: 0.95rem; margin: 22px 0 8px;';\n    var ZELLE = 'padding: 5px 12px 5px 0; color: var(--text-secondary, #a0a0b0); font-size: 0.87rem;';\n    var ZELLE_WERT = 'padding: 5px 12px 5px 0; color: var(--text-primary, #e8e8ee); font-size: 0.87rem; font-family: monospace; word-break: break-all;';\n    var KASTEN = 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-radius: 8px; padding: 14px 16px; margin: 0 0 10px;';\n    var GUT = ' color: #7ee787;', WARN = ' color: #ffa94d;', ROT = ' color: #ff7b72;', GRAU = ' color: #8a8a99;';\n    var FARBEN = { hoch: '#ff7b72', mittel: '#ffa94d', niedrig: '#e3b341', info: '#8a8a99', gut: '#7ee787' };\n    var URTEIL = { gut: GUT, warnung: WARN, kritisch: ROT };\n    function gitter(sp) { return el('div', 'display: grid; grid-template-columns: ' + sp + '; gap: 0 18px; align-items: baseline;'); }\n    function paar(g, n, w, stil) { g.appendChild(el('div', ZELLE, n)); g.appendChild(el('div', ZELLE_WERT + (stil || ''), w)); }\n\n    function tabelle(b) {\n        var huelle = el('div', 'overflow-x: auto; margin: 0 0 6px;');\n        var t = el('table', 'border-collapse: collapse; width: 100%; min-width: 520px; font-size: 0.84rem;');\n        var kopf = el('tr', '');\n        [T.sp_host, T.sp_anzahl, T.sp_aktiv, T.sp_preconnect].forEach(function (n) {\n            kopf.appendChild(el('th', 'text-align: left; padding: 6px 12px 6px 0; color: #8a8a99; font-weight: 700; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.4px; border-bottom: 1px solid var(--border, #2a2a35); white-space: nowrap;', n));\n        });\n        t.appendChild(kopf);\n        b.fremde.forEach(function (z) {\n            var r = el('tr', '');\n            function zelle(txt, stil) { r.appendChild(el('td', 'padding: 7px 12px 7px 0; border-bottom: 1px solid var(--border, #2a2a35); font-family: monospace; color: var(--text-primary, #e8e8ee);' + (stil || ''), txt)); }\n            zelle(z.host, ' word-break: break-all;');\n            zelle(String(z.anzahl !== null ? z.anzahl : '-'), GRAU);\n            zelle(String(z.aktiv !== null ? z.aktiv : '-'), (z.aktiv) ? WARN : GRAU);\n            zelle(z.preconnect ? T.wert_ja : T.wert_nein, z.preconnect ? GUT : GRAU);\n            t.appendChild(r);\n        });\n        huelle.appendChild(t);\n        return huelle;\n    }\n\n    function darstellen(b, ziel) {\n        ziel.innerHTML = '';\n        if (b.fehler) {\n            var txt = T['fehler_' + b.fehler] || T.fehler_unbekannt;\n            if (b.grund &#038;&#038; T['grund_' + b.grund]) { txt = txt + ' ' + T['grund_' + b.grund]; }\n            if (b.limit !== null) { txt = txt.replace('{limit}', String(b.limit)); }\n            ziel.appendChild(el('p', ZELLE + WARN + ' margin: 0;', txt));\n            return;\n        }\n        ziel.appendChild(el('div', 'font-size: 1.05rem; font-weight: 700; margin: 0 0 12px;' + URTEIL[b.urteil], T['urteil_' + b.urteil]));\n\n        var g = gitter('auto auto');\n        paar(g, T.zeile_seite, b.endurl || b.url, GRAU);\n        paar(g, T.zeile_teile, String(b.teile !== null ? b.teile : '-'), GRAU);\n        var arten = [];\n        ARTEN.forEach(function (a) { if (b.nachArt[a]) { arten.push((T['art_' + a] || a) + ': ' + b.nachArt[a]); } });\n        if (arten.length) { paar(g, T.zeile_nach_art, arten.join(', '), GRAU); }\n        paar(g, T.zeile_fremde, String(b.fremde.length), b.fremde.length ? WARN : GUT);\n        if (b.dauer !== null) { paar(g, T.zeile_dauer, b.dauer + ' ms', GRAU); }\n        if (b.limitRest !== null) { paar(g, T.zeile_limit, String(b.limitRest), GRAU); }\n        ziel.appendChild(g);\n\n        if (b.fremde.length) {\n            ziel.appendChild(el('div', UEBERSCHRIFT, T.h_fremde));\n            ziel.appendChild(tabelle(b));\n            ziel.appendChild(el('p', ZELLE + ' margin: 0 0 6px; font-size: 0.8rem;', T.tabelle_hinweis));\n        }\n\n        ziel.appendChild(el('div', UEBERSCHRIFT, T.h_befunde));\n        var irgendwas = false;\n        STUFEN.forEach(function (s) {\n            var gr = b.gruppen[s];\n            if (!gr.length) { return; }\n            irgendwas = true;\n            ziel.appendChild(el('div', 'font-weight: 700; font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.5px; margin: 14px 0 6px; color: ' + FARBEN[s] + ';', T['stufe_' + s] + ' (' + gr.length + ')'));\n            gr.forEach(function (f) {\n                var k = el('div', KASTEN + ' border-left: 3px solid ' + FARBEN[s] + ';');\n                var daten = {};\n                Object.keys(f.daten).forEach(function (n) { daten[n] = (n === 'url') ? kurz(f.daten[n]) : f.daten[n]; });\n                var t = text('befund_' + f.key, daten) || f.key;\n                var teile = t.split(' || ');\n                k.appendChild(el('div', 'color: var(--text-primary, #e8e8ee); font-size: 0.9rem; font-weight: 700;', teile[0]));\n                if (teile[1]) { k.appendChild(el('div', ZELLE + ' padding: 6px 0 0; line-height: 1.55;', teile[1])); }\n                ziel.appendChild(k);\n            });\n        });\n        if (!irgendwas) { ziel.appendChild(el('p', ZELLE + ' margin: 0;', T.keine_befunde)); }\n    }\n    window.LW_TEST.HERKUNFT.darstellen = darstellen;\n\n    var laeuft = false;\n    btn.addEventListener('click', function () {\n        if (laeuft) { return; }\n        laeuft = true; btn.disabled = true;\n        out.innerHTML = '';\n        out.appendChild(el('p', ZELLE + GRAU + ' margin: 0;', T.laeuft));\n        abfragen(wert('herkunft-url')).then(function (a) { darstellen(bewerten(a), out); laeuft = false; btn.disabled = false; },\n            function () { darstellen(bewerten({ fehler: 'netz' }), out); laeuft = false; btn.disabled = false; });\n    });\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Fetches a page once and sorts everything it pulls in by three questions: which host it comes from, whether it travels over http on an https page, and whether a third-party script or stylesheet carries an integrity attribute. One request is enough, because the answers are in the markup \u2014 which also means anything a script loads later stays invisible.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":38,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"tags":[91279,92757,91315],"class_list":["post-15704","page","type-page","status-publish","hentry","tag-prywatnosc-danych-pl","tag-web-development","tag-web-performance"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Third-Party Origin &amp; Subresource Integrity Checker: who a page loads from, and what it trusts - Lukas Wojcik - Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/third-party-origin-integrity-checker\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Third-Party Origin &amp; Subresource Integrity Checker: who a page loads from, and what it trusts - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"Fetches a page once and sorts everything it pulls in by three questions: which host it comes from, whether it travels over http on an https page, and whether a third-party script or stylesheet carries an integrity attribute. One request is enough, because the answers are in the markup \u2014 which also means anything a script loads later stays invisible.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/third-party-origin-integrity-checker\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/third-party-origin-integrity-checker\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/third-party-origin-integrity-checker\\\/\",\"name\":\"Third-Party Origin & Subresource Integrity Checker: who a page loads from, and what it trusts - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-09-05T23:12:16+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/third-party-origin-integrity-checker\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/third-party-origin-integrity-checker\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/third-party-origin-integrity-checker\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Toolbox\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Third-Party Origin &#038; Subresource Integrity Checker: who a page loads from, and what it trusts\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"luky\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"luky\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Third-Party Origin & Subresource Integrity Checker: who a page loads from, and what it trusts - Lukas Wojcik - Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/third-party-origin-integrity-checker\/","og_locale":"en_US","og_type":"article","og_title":"Third-Party Origin & Subresource Integrity Checker: who a page loads from, and what it trusts - Lukas Wojcik - Blog","og_description":"Fetches a page once and sorts everything it pulls in by three questions: which host it comes from, whether it travels over http on an https page, and whether a third-party script or stylesheet carries an integrity attribute. One request is enough, because the answers are in the markup \u2014 which also means anything a script loads later stays invisible.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/third-party-origin-integrity-checker\/","og_site_name":"Lukas Wojcik - Blog","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/third-party-origin-integrity-checker\/","url":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/third-party-origin-integrity-checker\/","name":"Third-Party Origin & Subresource Integrity Checker: who a page loads from, and what it trusts - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-09-05T23:12:16+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/third-party-origin-integrity-checker\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/third-party-origin-integrity-checker\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/third-party-origin-integrity-checker\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Toolbox","item":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/"},{"@type":"ListItem","position":3,"name":"Third-Party Origin &#038; Subresource Integrity Checker: who a page loads from, and what it trusts"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"luky","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"luky"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/15704","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=15704"}],"version-history":[{"count":0,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/15704\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/38"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=15704"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=15704"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}