ASP.NET
MVC
Razor
HTML Encoding
Web Development

ASP.NET MVC Razor render without encoding

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Razor encodes output by default, and that default is one of the most important protections against cross site scripting. Sometimes you must render rich text, so unencoded output is required for trusted content. The safe approach is to make raw rendering explicit, isolated, and backed by sanitization.

Why Razor Encodes By Default

When you write @Model.Body, Razor converts dangerous characters into safe text representation. This prevents user supplied scripts from being interpreted by the browser. If you bypass encoding too early, an attacker can execute JavaScript in another user session.

That is why @Html.Raw(...) should never be a casual formatting tool. It is a security decision point.

Correct Pattern: Sanitize Then Render

If content comes from users, sanitize it on the server using an allow list. Keep only the tags and attributes you explicitly accept.

A small service layer keeps this policy in one place.

csharp
1using Ganss.Xss;
2
3public interface IRichTextSanitizer
4{
5    string Sanitize(string input);
6}
7
8public sealed class RichTextSanitizer : IRichTextSanitizer
9{
10    private readonly HtmlSanitizer _sanitizer;
11
12    public RichTextSanitizer()
13    {
14        _sanitizer = new HtmlSanitizer();
15        _sanitizer.AllowedTags.Clear();
16        _sanitizer.AllowedTags.Add("p");
17        _sanitizer.AllowedTags.Add("ul");
18        _sanitizer.AllowedTags.Add("li");
19        _sanitizer.AllowedTags.Add("strong");
20        _sanitizer.AllowedTags.Add("em");
21        _sanitizer.AllowedAttributes.Clear();
22        _sanitizer.AllowedAttributes.Add("href");
23    }
24
25    public string Sanitize(string input)
26    {
27        return _sanitizer.Sanitize(input ?? string.Empty);
28    }
29}

In your controller, map raw input to a sanitized view model field.

csharp
1public sealed class ArticleViewModel
2{
3    public string Title { get; init; } = string.Empty;
4    public string SanitizedHtml { get; init; } = string.Empty;
5}
6
7public class ArticleController : Controller
8{
9    private readonly IRichTextSanitizer _sanitizer;
10
11    public ArticleController(IRichTextSanitizer sanitizer)
12    {
13        _sanitizer = sanitizer;
14    }
15
16    public IActionResult Details()
17    {
18        var raw = "<p>Hello <strong>world</strong></p>";
19        var model = new ArticleViewModel
20        {
21            Title = "Demo",
22            SanitizedHtml = _sanitizer.Sanitize(raw)
23        };
24        return View(model);
25    }
26}

In Razor, use default encoding for normal fields and raw output only for the sanitized field.

cshtml
1@model ArticleViewModel
2
3<h2>@Model.Title</h2>
4<div>@Html.Raw(Model.SanitizedHtml)</div>

Trusted HTML Versus User HTML

Not all raw HTML has equal risk.

  • Trusted template fragments created by developers can be rendered directly.
  • User supplied content should be sanitized every time it is accepted or rendered.
  • Third party content should be treated as untrusted unless you have strict validation rules.

Keep these paths separate in code. A field named SanitizedHtml is safer than a generic field named Content because it signals expectation and review intent.

Prefer IHtmlContent For Internal Helpers

If you build reusable view helpers, returning IHtmlContent can reduce accidental double encoding and make intent explicit.

csharp
1using Microsoft.AspNetCore.Html;
2
3public static class BadgeHtml
4{
5    public static IHtmlContent Info(string text)
6    {
7        var safe = System.Net.WebUtility.HtmlEncode(text);
8        return new HtmlString($"<span class=\"badge\">{safe}</span>");
9    }
10}

This helper still encodes dynamic text before wrapping it in markup.

Security Checks You Should Add

Raw rendering should have automated tests.

  • Verify script tags are removed by sanitizer.
  • Verify dangerous attributes such as event handlers are stripped.
  • Verify allowed formatting tags remain.
  • Verify URLs are filtered according to policy.

Also add code review guidance that any new Html.Raw usage must point to trusted or sanitized input.

Common Pitfalls

  • Calling Html.Raw directly on request payload fields.
  • Sanitizing in the view instead of in a service or controller layer.
  • Allowing too many tags and attributes in the allow list.
  • Mixing trusted templates and untrusted user strings in one property.
  • Assuming client side editor filtering is a replacement for server side sanitization.

Summary

  • Razor default encoding is a core security feature.
  • Use raw rendering only for trusted or sanitized HTML.
  • Centralize sanitization policy in a dedicated service.
  • Make view model naming explicit so review intent is clear.
  • Add tests and review rules for every raw rendering path.

Course illustration
Course illustration

All Rights Reserved.