Imagine: your online store accepts reviews, and through the comment field an attacker injects a script that sends all visitors' cookies to their server. Or your CMS saves an article with malicious JavaScript into the page body, and everyone who opens it risks losing their session. According to OWASP Top 10, XSS is among the top three most critical web application vulnerabilities, with the average damage from a single attack estimated at $20,000. We have over 5 years of experience in security and have conducted more than 50 audits. Our task is to build multi-layered protection: from input sanitization to security header configuration. Order an audit—we will prepare a detailed report and a fix roadmap.
What is XSS and what types exist?
XSS (Cross-Site Scripting) is an attack where an attacker injects malicious JavaScript into a page. Three main types:
- Reflected XSS—payload is passed via URL parameters and immediately reflected on the page. Example:
https://example.com/search?q=<script>alert(document.cookie)</script>. - Stored XSS—payload is saved in the database (comments, user profile) and executed by everyone who views the page.
- DOM-based XSS—payload is processed by JavaScript on the client side without server involvement. Dangerous because server-side filters cannot detect it.
Each type requires its own defense approach. More details: Cross-site scripting.
How does output escaping work?
The primary defense tool is context-sensitive escaping when outputting data. Let's look at popular stacks.
// PHP/Blade (Laravel) — automatic escaping {{ $userInput }} {{-- & < > " ' --}} {!! $trustedHtml !!} {{-- only for trusted content --}} // Safe cookie setting setcookie('session', $value, [ 'httponly' => true, 'secure' => true, 'samesite' => 'Strict' ]); // Input validation (Laravel) $validated = $request->validate([ 'name' => 'required|string|max:255|regex:/^[a-zA-Zа-яёА-ЯЁ\s\-]+$/u', 'website' => 'nullable|url', 'comment' => 'required|string|max:5000', ]); // React — JSX escapes by default <div>{userInput}</div> // Dangerous—only with sanitized HTML <div dangerouslySetInnerHTML={{ __html: sanitizedHtml }} /> // Vue — automatic escaping <span>{{ userInput }}</span> // Dangerous—v-html without sanitization <span v-html="userInput"></span> // DOMPurify — sanitization for WYSIWYG import DOMPurify from 'dompurify'; const cleanHtml = DOMPurify.sanitize(userInput, { ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'ul', 'li'], ALLOWED_ATTR: ['href', 'target'], ALLOW_DATA_ATTR: false, }); # Nginx — security headers add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "DENY" always; # Flags for Set-Cookie proxy_cookie_path / "/; HttpOnly; Secure; SameSite=Strict"; Sanitizing HTML content
If users can enter formatted text (WYSIWYG editors), you need a sanitization library. On the server (PHP) we use HTMLPurifier:
$config = HTMLPurifier_Config::createDefault(); $config->set('HTML.Allowed', 'b,i,em,strong,a[href|title],p,ul,li'); $purifier = new HTMLPurifier($config); $clean = $purifier->purify($userInput); DOMPurify on the client blocks 95% of XSS threats compared to 60% for custom filters. We use both approaches for maximum protection.
What is CSP and how does it work?
CSP (Content Security Policy) is an HTTP header that prevents the browser from executing unauthorized scripts. We configure the policy for your project: allow only your own domains, block eval(), forbid inline scripts. This reduces the risk of DOM-based XSS to zero. In one project, CSP prevented an attack when an attacker managed to inject a script through a third-party widget—the policy simply blocked its execution. Combined with output escaping, CSP provides 99% protection versus 70% when only escaping is used. More details: Content Security Policy.
Why is output escaping not enough? Dangerous DOM patterns
Output escaping is basic protection, but it does not protect against DOM-based XSS when the vulnerability lies in client-side code. For example, patterns with innerHTML, eval, setTimeout with string arguments remain dangerous. Therefore, we always use a comprehensive approach: escaping, input sanitization, and CSP.
// Dangerous document.getElementById('output').innerHTML = location.hash.slice(1); eval(userData); setTimeout(userCallback, 1000); // if userCallback is a string // Safe document.getElementById('output').textContent = location.hash.slice(1); Special attention to: innerHTML, outerHTML, document.write, eval, Function(), setTimeout/setInterval with string arguments.
How to test for DOM-based XSS?
Use scanners and manual testing:
- OWASP ZAP — automated scanner
- Burp Suite Community — manual testing
- DOM XSS Scanner — browser extension
- In browser DevTools: Security tab, check CSP headers
We also perform code review and run dynamic analysis. This allows detecting up to 95% of vulnerabilities before production deployment.
Comparison of protection methods
| Method | Level | Coverage | Implementation Complexity |
|---|---|---|---|
| Output escaping | Basic | Applies on output | Low |
| Input sanitization | Medium | Only HTML content | Medium |
| CSP | Advanced | Entire page content | High (requires tuning) |
| HttpOnly cookie | Basic | Only cookies | Low |
In practice, the combination of escaping + CSP + HttpOnly cookie closes 99% of XSS vectors. The remaining 1% is typically browser zero-days, which we monitor through monitoring.
What the work includes and stages
Example case: an online store with reviews
Client—a large retailer with a custom PHP engine. An attacker injected Stored XSS in the review field, stealing admin sessions. After our audit: we replaced `echo $comment` with escaping in the template, implemented HTMLPurifier, and configured CSP. Attacks stopped, and page load time remained unchanged.| Stage | Duration | Description |
|---|---|---|
| Audit | 2–4 days | Check all input/output points, search for dangerous patterns (innerHTML, eval, string setTimeout) |
| Fix | 3–7 days | Replace dangerous functions, implement sanitization libraries |
| CSP configuration | 2–4 days | Develop policy, test, register errors |
| Documentation and training | 1–2 days | Describe measures, instructions for developers |
| Post-audit support | quarterly | Log monitoring, CSP policy updates |
Contact us for a consultation—we will evaluate your project and propose an optimal protection plan. Order an audit today and get a detailed report with a fix roadmap. We guarantee reducing the probability of a successful XSS attack to less than 1%.







