🔐The Essential Guide to XSS Protection in Laravel (Don’t Get Hacked!)

  

Cross-Site Scripting (XSS) is one of the most common and dangerous web security vulnerabilities. It allows attackers to inject malicious scripts into web pages viewed by other users. If not properly handled, XSS can lead to session hijacking, defacement, and even redirecting users to malicious websites.

💡 What is Cross-Site Scripting (XSS)?

XSS occurs when untrusted data (often from user input) is injected into a web page without proper validation or escaping. This can allow attackers to execute malicious JavaScript in the context of another user’s session.

🧰 Types of XSS Attacks

  • Stored XSS — Malicious scripts are stored in a database and served to users.
  • Reflected XSS — The script is reflected off the server (e.g., via query params).
  • DOM-based XSS — The attack occurs on the client side through JavaScript manipulating the DOM.

🧨 1. Stored XSS (Persistent XSS)

Stored XSS occurs when malicious scripts are saved (persisted) on the server, usually in a database, and later displayed to users without proper sanitization or escaping.

📌 How it works:

  • An attacker submits malicious JavaScript (e.g., in a comment or user profile).
  • The script is stored in the database.
  • When another user loads the page, the server includes this content in the response without escaping.
  • The browser executes the script in the context of the logged-in user.

⚠️ Example:

A comment field allows this input:

comment field allows this input  

If this is stored and rendered directly like this:

stored and rendered 
The script will run for every user who views that comment.

🎯 Target:

Other users of the system.

🔁 2. Reflected XSS (Non-Persistent XSS)

Reflected XSS happens when user-supplied data is immediately returned by the server without proper validation or encoding. Unlike Stored XSS, it is not saved, but reflected in the response.

📌 How it works:

  • An attacker crafts a URL containing a malicious script in a query string or form input.
  • A user is tricked into clicking the link.
  • The server reflects the input back in the response without sanitization.
  • The browser executes the script.

⚠️ Example:

Reflected XSS  

If the server echoes q without escaping:

 
Then the script runs immediately when the page loads.

🎯 Target:

A specific victim, often via phishing or malicious links.

🧬 3. DOM-Based XSS

DOM-based XSS is a client-side vulnerability that happens within the browser, where JavaScript modifies the DOM using untrusted data without proper handling.

📌 How it works:

  • The page’s JavaScript reads data from the URL, cookies, or user input.
  • It dynamically writes that data into the page’s DOM.
  • If this is done without sanitization, malicious code can be executed.

⚠️ Example (client-side JS):

 

A malicious URL like:

malicious URL 
Will execute the script because it’s directly inserted into the DOM.

🎯 Target:

The current user’s session in their own browser.

🧪 Scenario: A basic comment system vulnerable to Stored XSS

🧱 Step 1: Create the database and migration

Run the following Artisan command:

Artisan command  

Then update the migration:

update the migration 

Run migration:

Run migration 

📥 Step 2: Create the controller

Create the controller 

Then in CommentController.php:

CommentController 

🔧 Step 3: Add fillable fields to Comment model

Add fillable fields  

🖼️ Step 4: Create the Blade view

Create the Blade view  

🌐 Step 5: Define the routes

In routes/web.php:

Define the routes 

🧪 Test the Stored XSS

Test the Stored XSS 

  • Submit the comment.

⚠️ You will see an alert pop up — this is the injected JavaScript executing from the database when the page loads. This simulates a Stored XSS attack.

Use Escaped Output ({{ }})

🛡️ How Laravel Helps Prevent XSS

Laravel comes with built-in protections against most XSS attacks. Here’s how to take full advantage of them:

✅ 1. Use Escaped Output ({{ }})

Laravel’s Blade template engine escapes output by default:

 
This prevents the browser from interpreting malicious scripts. 

❌ Do NOT use {!! !!} unless absolutely necessary. It outputs raw HTML and can be dangerous if the data isn’t sanitized.

✅ 2. Sanitize Input (Use strip_tags or Purifier)

If you must allow some HTML (e.g., bold or italic tags), sanitize user input:

Sanitize Input 

Or better yet, use the Laravel Purifier package to allow safe HTML:

Laravel Purifier 

In controller:

In controller 

✅ 3. Use CSRF Protection (For XSS Chains)

While CSRF (Cross-Site Request Forgery) is a separate issue, attackers often chain XSS with CSRF to perform unauthorized actions.

Laravel automatically protects against CSRF using a hidden token in forms:

Use CSRF Protection  

✅ 4. Validate Input Properly

Laravel’s FormRequest validation can be used to restrict unwanted input:

Validate Input Properly  

✅ 5. Set Content Security Policy (CSP)

A CSP header restricts what scripts can be loaded and executed, preventing XSS even if a malicious script sneaks in.

Use Laravel middleware to set it:

Set Content Security Policy  
For advanced setup, use packages like spatie/laravel-csp.

🧪 Example: Secure Comment Submission

Secure Comment Submission 

XSS Prevention 

✅ Summary: XSS Prevention in Laravel

  • ✅ Use {{ }} for output, not {!! !!}
  • ✅ Sanitize input using Purifier
  • ✅ Validate input with Laravel’s validator
  • ✅ Use CSRF tokens in all forms
  • ✅ Add a strict Content Security Policy (CSP)
  • ✅ Don’t trust user input — ever

✍️ Final Thoughts

XSS is a dangerous but preventable vulnerability. Laravel provides excellent tools out-of-the-box, but developers must understand the risks and implement secure coding practices consistently.

By following the above guidelines, you can keep your Laravel application safe from Cross-Site Scripting and protect your users’ data.

If you found this helpful, feel free to share or drop a comment. Happy coding with Laravel! 🧱✨

Read More Article