November 2, 2026
Who Can Change the Code on Your Website?
Published by the HackerMe team (Agura), the makers of HackerMe, a free automated website security scanner. The checks below are…

By HackerMe
3 min read
- 1 Who Can Change the Code on Your Website? Third-Party Scripts, Subresource Integrity, and What a Pass Doesn't Prove
- 2 1. List what loads (safe on any public site)
- 3 2. Integrity and crossorigin attributes (safe on any public site)
- 4 3. Does the hash match the file? (safe on any public site)
- 5 4. Pinned versions versus moving URLs (safe on any public site, plus maintainer check)
Who Can Change the Code on Your Website? Third-Party Scripts, Subresource Integrity, and What a Pass Doesn't Prove
Published by the HackerMe team (Agura), the makers of HackerMe, a free automated website security scanner. The checks below are vendor-neutral. Each one is labeled safe on any public site (it only reads what the site sends to every visitor) or maintainer check (it needs access to the code, the build or vendor accounts).
You added a chat widget to your site a year ago. Who can change the code it runs for your visitors today?
If the tag points to the vendor's server, the answer is whoever controls that server. The script runs with the same privileges as your own code, and the OWASP Third Party JavaScript Management Cheat Sheet names a compromise of the third-party server as the single greatest risk. Subresource Integrity (SRI) answers part of that: you put a hash of the file in the tag, and if the file stops matching, the browser refuses to run it (MDN: Subresource Integrity, W3C SRI).
1. List what loads (safe on any public site)
A quick first pass over the initial HTML (it also lists same-site files):
curl -fsSL https://example.com/ | grep -oiE '<(script|link)[^>]+(src|href)=[^ >]+'curl -fsSL https://example.com/ | grep -oiE '<(script|link)[^>]+(src|href)=[^ >]+'This is not a full inventory: it misses tags split across lines, unusual quoting, and scripts inserted at runtime, for example by a tag manager. For a fuller view, load the page in a browser and run this in the dev tools console, then check the Network tab:
[...document.scripts].map(s => s.src).filter(Boolean)[...document.scripts].map(s => s.src).filter(Boolean)- Expected: only hosts you recognize and can name an owner for.
- Finding: a host nobody can explain. OWASP notes that an abandoned script domain can be re-registered by someone else, who can then publish code to it.
- Doesn't prove: completeness. Some scripts load only after login or consent.
2. Integrity and crossorigin attributes (safe on any public site)
<script src="https://cdn.example.net/lib@3.2.1/lib.min.js"
integrity="sha384-..." crossorigin="anonymous"></script><script src="https://cdn.example.net/lib@3.2.1/lib.min.js"
integrity="sha384-..." crossorigin="anonymous"></script>- Expected:
integritywith asha256,sha384orsha512value, pluscrossorigin. Cross-origin SRI requires CORS, so withoutcrossoriginthe load fails (MDN: crossorigin). - Finding: a third-party file with no
integrity. Treat it as a decision to review, not an automatic vulnerability. - Doesn't prove: that the file is safe. A hash proves only that it is the file you hashed.
3. Does the hash match the file? (safe on any public site)
curl -fsSL -o lib.min.js -w '%{http_code} %{content_type} %{url_effective}\n' \
https://cdn.example.net/lib@3.2.1/lib.min.js
head -c 200 lib.min.js; echo
openssl dgst -sha384 -binary lib.min.js | openssl base64 -A; echocurl -fsSL -o lib.min.js -w '%{http_code} %{content_type} %{url_effective}\n' \
https://cdn.example.net/lib@3.2.1/lib.min.js
head -c 200 lib.min.js; echo
openssl dgst -sha384 -binary lib.min.js | openssl base64 -A; echo-L follows redirects, and -f makes curl fail on an HTTP error instead of saving an error page, so you never hash a 404 page by mistake. Confirm the final URL, the 200 status, a JavaScript content type, and that the first bytes look like the library you expect.
- Expected: the digest equals the value after
sha384-in the page. - Finding: a mismatch. The browser blocks the file, which is SRI working as designed. See the illustration below before you touch the hash.
4. Pinned versions versus moving URLs (safe on any public site, plus maintainer check)
SRI protects you whatever the URL looks like: if the bytes change, the file is blocked. What a moving URL such as /latest/sdk.js affects is operations. Every vendor release fails the check until someone updates the hash. Pinned versions, or a self-hosted copy that changes only when you deploy (OWASP lists in-house mirroring as a defense), make SRI practical to keep.
- Finding: an unpinned third-party URL with no plan for how changes are reviewed.
- Doesn't prove: that the pinned version is current. Known-vulnerable components are covered by OWASP Top 10:2025 A03 Software Supply Chain Failures.
5. Tag managers and vendor accounts (maintainer check)
Tag manager scripts can change without a deployment, and OWASP notes that the pace of tag changes can make SRI impractical.
- Expected: few people with publish rights, two-factor authentication, and changes reviewed like application code.
- Finding: shared logins or former staff who can still publish.
6. Policy headers as a second layer (safe on any public site to read, maintainer check to change)
curl -fsSI https://example.com/ | grep -i -E '^(content-security-policy|integrity-policy)'curl -fsSI https://example.com/ | grep -i -E '^(content-security-policy|integrity-policy)'A CSP script-src can limit which hosts serve scripts (MDN: script-src). The newer Integrity-Policy header can block scripts loaded without integrity metadata, but MDN marks it as limited availability: it is not supported in every major browser. Its absence is not a security failure, and a missing CSP is a prompt to review, not proof of a weakness. If you adopt it, start with Integrity-Policy-Report-Only.
- Doesn't prove: that an allowed host can't serve malicious code. An allow list limits where code comes from, not what it does.
Illustration: the browser blocks a file
This is a constructed example to show the process, not a check run on any customer site.
Your checkout page loads lib@3.2.1/lib.min.js from a CDN with a sha384 hash. One morning a feature breaks and the console shows an integrity error for that file. The quick fix is to paste in a new hash. Don't, yet:
- Download it again with check 3 and confirm you got the real file, not an error page or an unexpected redirect.
- Ask why the bytes changed. A fixed-version URL should not change content. A changed
latestURL is expected, but unreviewed. - Hash an independent copy of the same version, for example from the project's official release or package registry.
- Diff it against the copy you last reviewed. Look for new network calls, input handling or obfuscated code.
- Update the hash only once the change is explained. If it isn't, leave the block in place, serve your last reviewed copy yourself and contact the vendor.
The block was the protection working. Replacing the hash blindly turns it off.
Make it routine
Re-run the inventory after releases and when marketing tools change, and keep a list of third-party hosts with owners. A clean result is a starting point, not a guarantee.
Disclosure: we are the team behind HackerMe, a free automated website security scanner: https://hackerme.ai
The checks above work without it. What would you add to this list? We would like to hear it in the comments.