← Back to Articles         
Prevent XSS in Razor Views

Prevent XSS in Razor Views

Published on 27 Sep 2026     3 min read ASP.NET Core MVC
MVC

Cross-Site Scripting (XSS) occurs when an application displays untrusted input as executable HTML or JavaScript.

For example, an attacker submits:

<script>stealCookies()</script>

If the browser executes it, the attacker may steal session information, modify the page, or redirect the user.

1. Use Razor’s automatic HTML encoding

Razor automatically HTML-encodes values displayed using @.

<p>@Model.Comment</p>

If Model.Comment contains:

<script>alert('Hacked')</script>

Razor generates:

&lt;script&gt;alert('Hacked')&lt;/script&gt;

The browser displays it as text instead of executing it. Razor and Tag Helpers automatically encode variable output by default. Microsoft Learn

2. Avoid Html.Raw() with untrusted content

This is dangerous:

@Html.Raw(Model.Comment)

Html.Raw() bypasses Razor’s automatic encoding. If Comment contains a script, the browser may execute it.

Use this instead:

@Model.Comment

Also avoid creating HtmlString objects from user-controlled content because they are not automatically encoded.

3. Sanitize content when HTML must be allowed

Some applications intentionally accept formatted HTML, such as:

  • Blog articles
  • Rich-text editor content
  • Product descriptions

In that situation, normal Razor encoding would display the HTML tags as text. Before using Html.Raw(), sanitize the content with an allow-list-based HTML sanitizer.

var safeHtml = sanitizer.Sanitize(model.Content);

Then render only the sanitized value:

@Html.Raw(Model.SanitizedContent)

A commonly used third-party package is:

dotnet add package HtmlSanitizer

Example:

using Ganss.Xss;

var sanitizer = new HtmlSanitizer();
var safeContent = sanitizer.Sanitize(article.Content);

HtmlSanitizer is an external NuGet library; it is not built into ASP.NET Core.

For your portfolio’s TinyMCE article content, this sanitization step is particularly important because the content is intentionally rendered as HTML.

4. Validate input—but don’t rely on validation alone

Use ViewModel validation to restrict expected input:

public class CommentViewModel
{
    [Required]
    [StringLength(500)]
    public string Comment { get; set; } = string.Empty;
}

Validation helps reject unexpected input, but it does not replace output encoding or sanitization. Microsoft recommends encoding untrusted content at output even when it has already been validated or sanitized.

5. Handle JavaScript values safely

Avoid inserting untrusted input directly into JavaScript:

<script>
    const name = '@Model.Name'; // unsafe context
</script>

A safer approach is to store the encoded value in a data attribute:

<div id="user-data" data-name="@Model.Name"></div>

<script>
    const element = document.getElementById("user-data");
    const name = element.dataset.name;

    document.getElementById("result").textContent = name;
</script>

Prefer safe DOM properties:

element.textContent = userInput;

Avoid dangerous DOM operations with untrusted input:

element.innerHTML = userInput;
document.write(userInput);

6. Use Tag Helpers for attributes and URLs

<a asp-controller="Product"
   asp-action="Details"
   asp-route-id="@Model.Id">
    Details
</a>

Tag Helpers apply appropriate encoding when generating attributes. Avoid manually concatenating untrusted values into HTML, JavaScript, or URLs.

7. Add a Content Security Policy

A Content Security Policy provides an additional layer of protection by controlling which scripts the browser may execute.

Example response header:

Content-Security-Policy: default-src 'self'; script-src 'self'

CSP is defence in depth. It does not replace output encoding and sanitization.

Key points

  • Display normal values using @Model.Property.
  • Never use Html.Raw() with untrusted or unsanitized content.
  • Sanitize rich HTML before rendering it.
  • Encode at output; do not store pre-encoded values in the database.
  • Avoid placing untrusted values directly inside JavaScript.
  • Use textContent instead of innerHTML.
  • Validate input, but never treat validation alone as XSS protection.
  • Consider CSP as an additional security layer.

Interview answer

Razor prevents XSS by automatically HTML-encoding values rendered with the @ syntax. Developers must avoid bypassing this protection with Html.Raw() or HtmlString. If rich HTML must be displayed, it should first be sanitized with an allow-list-based sanitizer. JavaScript, URLs and HTML attributes must also use context-appropriate encoding.

 

← Back to Articles