Frontend JavaScript/TypeScript Web Security Spec (Vanilla Browser JS/TS, Modern Browsers)
This document is designed as a security spec that supports:
- Secure-by-default code generation for new frontend JavaScript/TypeScript (no specific framework assumed).
- Security review / vulnerability hunting in existing frontend code (passive “notice issues while working” and active “scan the repo and report findings”).
It is intentionally written as a set of normative requirements (“MUST/SHOULD/MAY”) plus audit rules (what bad patterns look like, how to detect them, and how to fix/mitigate them).
0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)
MUST NOT request, output, log, hard-code, or commit secrets (API keys intended to be secret, private keys, passwords, OAuth refresh tokens, session tokens, cookies). Notes:
- Frontend code is inherently observable by end users. If a value must remain secret, it must not be in browser-delivered code.
- If the project uses “public” keys (e.g., publishable analytics keys), they MUST be treated as non-secret and scoped accordingly.
MUST NOT “fix” security by disabling protections (e.g., weakening CSP with
unsafe-inline/unsafe-evalwithout justification, removing origin checks forpostMessage, switching toinnerHTMLfor convenience, accepting arbitrary redirects/URLs, or turning off sanitization).MUST provide evidence-based findings during audits: cite file paths, code snippets, and relevant HTML/CSP/config values that justify the claim.
MUST treat uncertainty honestly:
- Security headers (CSP, frame-ancestors, etc.) might be set by server/edge/CDN rather than in repo code. If not visible, report as “not visible here; verify at runtime/edge config.” (Also note that
<meta http-equiv=...>only simulates a subset of headers; don’t assume other security headers exist just because a meta tag exists.) (MDN Web Docs)
- Security headers (CSP, frame-ancestors, etc.) might be set by server/edge/CDN rather than in repo code. If not visible, report as “not visible here; verify at runtime/edge config.” (Also note that
1) Operating modes
1.1 Generation mode (default)
When asked to write new frontend JS/TS code or modify existing code:
- MUST follow every MUST requirement in this spec.
- SHOULD follow every SHOULD requirement unless the user explicitly says otherwise.
- MUST prefer safe-by-default browser APIs and proven libraries over custom security code (especially for HTML sanitization).
- MUST avoid introducing new risky sinks (DOM XSS injection sinks like
innerHTML, navigation tojavascript:URLs, dynamic code execution viaeval/Function, unsafepostMessage, unsafe third-party script loading, etc.). (OWASP Cheat Sheet Series)
1.2 Passive review mode (always on while editing)
While working anywhere in a frontend repo (even if the user did not ask for a security scan):
- MUST “notice” violations of this spec in touched/nearby code.
- SHOULD mention issues as they come up, with a brief explanation + safe fix.
1.3 Active audit mode (explicit scan request)
When the user asks to “scan”, “audit”, or “hunt for vulns”:
- MUST systematically search the codebase for violations of this spec.
- MUST output findings in a structured format (see §2.3).
Recommended audit order:
- HTML entrypoints (
index.html, server-rendered templates), script/style includes, and any CSP delivery (header vs meta). (W3C) - DOM XSS sinks (
innerHTML,document.write,insertAdjacentHTML, event-handler attributes) and their data sources (URL params/hash, storage, postMessage, API responses). (OWASP Cheat Sheet Series) - Navigation/redirect handling (
window.location*, link targets, URL allowlists) includingjavascript:URL hazards. (MDN Web Docs) - Cross-origin communication (
postMessage, iframe embed patterns, sandboxing). (MDN Web Docs) - Storage of sensitive data (localStorage/sessionStorage) and assumptions about trust. (OWASP Cheat Sheet Series)
- Third-party scripts / tag managers / CDNs, and integrity controls (SRI) and policy controls (CSP). (OWASP Cheat Sheet Series)
- DOM clobbering gadgets and unsafe reliance on
window/documentnamed properties. (OWASP Cheat Sheet Series)
2) Definitions and review guidance
2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)
Examples include:
- URL-derived data:
location.href,location.search,location.hash,document.baseURI,new URLSearchParams(location.search), routing fragments. (OWASP Cheat Sheet Series) - DOM content that may include user-controlled markup (comments, profiles, CMS content, markdown-to-HTML output, etc.), especially if inserted dynamically. (OWASP Cheat Sheet Series)
postMessageevent data (event.data) and metadata (event.origin) from other windows/frames. (MDN Web Docs)- Browser storage:
localStorage,sessionStorage, IndexedDB (contents can be attacker-influenced via XSS or local machine access; never treat as “trusted”). (OWASP Cheat Sheet Series) - Any data returned from network calls (even if from “your API”), because it may contain stored attacker content that becomes dangerous only when inserted into the DOM. (OWASP Cheat Sheet Series)
2.2 Dangerous sink (DOM XSS / code execution sink)
A sink is any API/operation that can execute script or interpret attacker-controlled strings as HTML/JS/URL in a security-sensitive way. High-signal sinks include:
- HTML parsing / insertion:
innerHTML,outerHTML,insertAdjacentHTML,document.write,document.writeln. (OWASP Cheat Sheet Series) - Dynamic code execution:
eval,new Function,setTimeout("..."),setInterval("..."). (MDN Web Docs) - Navigation to script-bearing URLs (e.g.,
javascript:) via setters likeLocation.href/window.location(and via linkhrefif attacker-controlled). (MDN Web Docs) - Setting event handler attributes from strings, e.g.
setAttribute("onclick", "..."). (OWASP Cheat Sheet Series)
2.3 Required audit finding format
For each issue found, output:
- Rule ID:
- Severity: Critical / High / Medium / Low
- Location: file path + function/class/module + line(s)
- Evidence: the exact code/config snippet
- Impact: what could go wrong, who can exploit it
- Fix: safe change (prefer minimal diff)
- Mitigation: defense-in-depth if immediate fix is hard
- False positive notes: what to verify if uncertain
3) Secure baseline: minimum production configuration (MUST in production)
This is the smallest baseline that prevents common frontend JS/TS security misconfigurations. Some items are “in repo” (HTML/JS) and some may live at the server/edge.
3.1 Content Security Policy (CSP) baseline (SHOULD; MUST for high-risk apps)
SHOULD deliver CSP via HTTP response headers when possible.
MAY deliver CSP via an HTML
<meta http-equiv="Content-Security-Policy" ...>tag when you cannot set headers (e.g., purely static hosting constraints). (MDN Web Docs)If using CSP via
<meta http-equiv>, MUST understand the limitations:- The policy only applies to content that follows the meta element (so it must appear very early, before any scripts/resources you want governed). (W3C)
- The following directives are not supported in a meta-delivered policy and will be ignored:
report-uri,frame-ancestors, andsandbox. (W3C) - “Report-only” CSP cannot be set via a meta element. (W3C)
Practical baseline goals:
- Avoid script sources
unsafe-inlineandunsafe-eval(they significantly weaken CSP’s value against XSS). (MDN Web Docs) - Prefer nonce- or hash-based script policies if you need inline scripts. (MDN Web Docs)
- Consider enabling Trusted Types enforcement where feasible. (MDN Web Docs)
3.2 Third-party scripts baseline (SHOULD)
- SHOULD minimize third-party script execution and treat it as equivalent privilege to first-party JS (it runs with your origin’s privileges). (OWASP Cheat Sheet Series)
- SHOULD use Subresource Integrity (SRI) for third-party scripts/styles loaded from CDNs. (MDN Web Docs)
3.3 Cross-window communication baseline (SHOULD)
- SHOULD restrict
postMessagecommunications to explicit origins, and validate both origin and message shape. (MDN Web Docs)
4) Rules (generation + audit)
Each rule contains: required practice, insecure patterns, detection hints, and remediation.
JS-XSS-001: Do not inject untrusted HTML into the DOM (avoid innerHTML and friends)
Severity: Critical if you can prove attacker-controlled input can reach these APIs; otherwise Medium
Required:
MUST treat
innerHTML,outerHTML, andinsertAdjacentHTMLas dangerous sinks when their input can contain untrusted data. (OWASP Cheat Sheet Series)MUST prefer safe DOM APIs that do not parse HTML:
textContentfor text. (OWASP Cheat Sheet Series)document.createElement,appendChild,setAttributefor non-event-handler attributes. (OWASP Cheat Sheet Series)
If HTML insertion is truly required, SHOULD sanitize with a well-reviewed HTML sanitizer and strongly consider enforcing Trusted Types to confine usage to audited code paths. (MDN Web Docs)
Insecure patterns:
el.innerHTML = userInputel.insertAdjacentHTML('beforeend', userInput)el.outerHTML = userInput
Detection hints:
- Search for:
.innerHTML,.outerHTML,insertAdjacentHTML(. - Trace the origin of inserted string: URL params/hash, postMessage, storage, API responses, DOM attributes. (OWASP Cheat Sheet Series)
Fix:
Replace with
textContentfor plain text. (OWASP Cheat Sheet Series)For structured UI, build DOM nodes explicitly.
For “rich text” requirements:
- Sanitize using an allowlist-based sanitizer.
- Prefer returning safe “components” instead of arbitrary HTML strings.
- Use Trusted Types enforcement to ensure only
TrustedHTMLreaches sinks where supported. (MDN Web Docs)
Mitigation:
- Deploy a strict CSP and consider Trusted Types enforcement (
require-trusted-types-for 'script'). (MDN Web Docs)
False positive notes:
- If the string is provably constant or fully generated from trusted constants, it may be safe. Still prefer safer APIs.
JS-XSS-002: Avoid document.write / document.writeln (XSS + document clobbering hazards)
Severity: Critical if you can prove attacker-controlled input can reach these APIs; otherwise Medium
Required:
- MUST avoid
document.write()anddocument.writeln()in production code (they are XSS vectors and can be abused with crafted HTML even if some browsers block injected `` with nointegrity. - Loading
latestor unpinned third-party resources.
Detection hints:
- Search for
<script src="https://and<link rel="stylesheet" href="https://withoutintegrity=. - Check whether
integrityis present and uses strong hashes (sha256/384/512 are typical). (MDN Web Docs)
Fix:
- Add
integrity="sha384-..."(or appropriate) and ensure proper CORS mode where needed. - Prefer self-hosting critical libraries.
FS-DOMC-001: Prevent DOM clobbering (avoid relying on window/document named properties)
Severity: Medium to High (can become Critical if it enables script loading or javascript: navigation)
Required:
- MUST NOT rely on implicit global variables or
window.someName/document.someNamelookups that can be clobbered by injected HTML elements with matchingid/name. (OWASP Cheat Sheet Series) - MUST avoid patterns like
let x = window.redirectTo || "/safe"; location.assign(x);whereredirectTocould be clobbered to an<a>element whosehrefis attacker-controlled (includingjavascript:). (OWASP Cheat Sheet Series) - SHOULD use explicit variable declarations, local scope, and explicit DOM queries (
getElementById) rather than named property access. (OWASP Cheat Sheet Series) - If the app inserts user-controlled markup (even sanitized), SHOULD ensure sanitization strategies consider
id/namecollisions. (OWASP Cheat Sheet Series)
Insecure patterns:
const cfg = window.config || \{\};used for security-sensitive URLs.const redirect = window.redirectTo || "/"; location.assign(redirect);(OWASP Cheat Sheet Series)- Loading scripts from
window.*config values without strict validation.
Detection hints:
- Search for
window.anddocument.used as config stores (especially||fallback patterns). - Search for usage of
location.assign/replacewith variables that come fromwindow/documentproperties. - Search for dynamic script creation (
createElement('script')) where.srccomes from a non-local variable. (OWASP Cheat Sheet Series)
Fix:
- Store config in module-scoped constants (not on
window/document) and pass it explicitly. - Validate any URL-like config with protocol/origin allowlists (see FEJS-URL-001). (OWASP Cheat Sheet Series)
- Consider hardening: sanitization, CSP, and (in limited cases) freezing sensitive objects, but treat these as defense-in-depth, not a substitute for safe coding patterns. (OWASP Cheat Sheet Series)
5) Practical scanning heuristics (how to “hunt”)
When actively scanning, use these high-signal patterns:
DOM XSS sinks:
.innerHTML,.outerHTML,insertAdjacentHTML(document.write(,document.writeln((OWASP Cheat Sheet Series)
Dangerous navigation / URL sinks:
window.location,location.href,location.assign,location.replacejavascript:literals (and other suspicious schemes likedata:text/html) (MDN Web Docs)
String-to-code execution:
eval(,new Function,setTimeout(",setInterval("(MDN Web Docs)
Event-handler string injection:
.setAttribute("on,.onclick =,.onload =with strings (OWASP Cheat Sheet Series)
postMessage:postMessage(with"*"as targetOriginaddEventListener("message"without strictevent.originallowlist checks (MDN Web Docs)
Storage:
localStorage.setItem(/getItem(,sessionStorage.*- keys containing
token,jwt,session,auth,refresh(OWASP Cheat Sheet Series)
CSP and related:
Content-Security-Policyheader config (server/edge)<meta http-equiv="Content-Security-Policy" ...>- CSP containing
unsafe-inlineorunsafe-eval require-trusted-types-for/trusted-typesdirectives (MDN Web Docs)
Third-party scripts:
<script src="https://...">withoutintegrity=- Tag manager snippets and dynamic script injection code paths (MDN Web Docs)
DOM clobbering gadgets:
window.<name> || ...anddocument.<name> || ...patterns- security-sensitive usage of
window/documentproperties as config sources (OWASP Cheat Sheet Series)
Always try to confirm:
- data origin (untrusted vs trusted),
- sink type (HTML parse, navigation, code execution, message handling, storage),
- protective controls present (CSP, Trusted Types, sanitizers, strict allowlists, schema validation).
6) Sources (accessed 2026-01-27)
Primary standards / platform docs:
- W3C Content Security Policy Level 2 (HTML
<meta>delivery restrictions; unsupported directives in meta CSP):https://www.w3.org/TR/CSP2/(W3C) - MDN: CSP Guide (strict CSP, nonces/hashes,
unsafe-inline/unsafe-eval, eval blocking):https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP(MDN Web Docs) - MDN:
<meta http-equiv>(CSP via meta and warning about meta-based security headers):https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta/http-equiv(MDN Web Docs) - MDN:
frame-ancestors(and note it’s not supported in<meta>):https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors(MDN Web Docs)
DOM XSS and dangerous sinks:
- OWASP: DOM Based XSS Prevention Cheat Sheet (dangerous sinks + safe patterns like
textContent):https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html(OWASP Cheat Sheet Series) - MDN:
innerHTML(security considerations):https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML(MDN Web Docs) - MDN:
insertAdjacentHTML(security considerations):https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML(MDN Web Docs) - MDN:
document.write()/document.writeln()(security considerations):https://developer.mozilla.org/en-US/docs/Web/API/Document/writeandhttps://developer.mozilla.org/en-US/docs/Web/API/Document/writeln(MDN Web Docs)
URL scheme hazards:
- MDN:
javascript:URLs (execution on navigation; discouraged; referenceswindow.location):https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript(MDN Web Docs)
Trusted Types:
- W3C: Trusted Types spec (DOM XSS sinks include
Element.innerHTMLandLocation.hrefsetters; goals and limitations):https://www.w3.org/TR/trusted-types/(W3C) - MDN:
require-trusted-types-fordirective:https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for(MDN Web Docs) - MDN:
trusted-typesdirective:https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/trusted-types(MDN Web Docs)
Cross-window messaging:
- MDN:
window.postMessage(security guidance: specify targetOrigin; validate origin):https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage(MDN Web Docs) - OWASP: HTML5 Security Cheat Sheet (Web Messaging guidance: explicit origin, strict checks, no
innerHTML):https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html(OWASP Cheat Sheet Series)
Third-party scripts and integrity:
- OWASP: Third Party JavaScript Management Cheat Sheet (risks and mitigations including SRI/mirroring):
https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html(OWASP Cheat Sheet Series) - MDN: Subresource Integrity overview:
https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity(MDN Web Docs) - W3C: Subresource Integrity spec:
https://www.w3.org/TR/sri-2/(W3C)
DOM clobbering:
- OWASP: DOM Clobbering Prevention Cheat Sheet (named property access risk; example attacks involving
location.assignandjavascript:):https://cheatsheetseries.owasp.org/cheatsheets/DOM_Clobbering_Prevention_Cheat_Sheet.html(OWASP Cheat Sheet Series)