Program: CWE-79
Project: CVE-2021-3646
Buggy source:
@inject LinkGenerator linkGenerator
@inject UserManager<ApplicationUser> UserManager
@inject ISettingsRepository SettingsRepository
@using BTCPayServer.HostedServices
@using BTCPayServer.Views.Notifications
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Abstractions.Contracts
@using BTCPayServer.Client
@using BTCPayServer.Services
@model BTCPayServer.Components.NotificationsDropdown.NotificationSummaryViewModel
@addTagHelper *, BundlerMinifier.TagHelpers

@if (Model.UnseenCount > 0)
{
    <li class="nav-item dropdown" id="notifications-nav-item">
        <a class="nav-link js-scroll-trigger @ViewData.IsActiveCategory(typeof(NotificationsNavPages))" href="#" id="NotificationsDropdownToggle" role="button" data-bs-toggle="dropdown">
            <span class="d-inline-block d-lg-none">Notifications</span>
            <i class="fa fa-bell d-lg-inline-block d-none"></i>
            <span class="notification-badge badge rounded-pill bg-danger">@Model.UnseenCount</span>
        </a>
        <div class="dropdown-menu dropdown-menu-end text-center notification-dropdown" aria-labelledby="NotificationsDropdownToggle">
            <div class="d-flex align-items-center justify-content-between py-3 px-4 border-bottom border-light"> 
                <h5 class="m-0">Notifications</h5>
                <form id="notificationsForm" asp-controller="Notifications" asp-action="MarkAllAsSeen" asp-route-returnUrl="@Context.Request.GetCurrentPathWithQueryString()" method="post">
                    <button class="btn btn-link p-0" type="submit">Mark all as seen</button>
                </form>
            </div>
            @foreach (var notif in Model.Last5)
            {
                <a asp-action="NotificationPassThrough" asp-controller="Notifications" asp-route-id="@notif.Id" class="notification d-flex align-items-center dropdown-item border-bottom border-light py-3 px-4">
                    <div class="me-3">
                        <vc:icon symbol="note" />
                    </div>

                    <div class="notification-item__content">
                        <div class="text-start text-wrap">
                            @notif.Body
                        </div>
                        <div class="text-start d-flex">
                            <small class="text-muted" data-timeago-unixms="@notif.Created.ToUnixTimeMilliseconds()">@notif.Created.ToTimeAgo()</small>
                        </div>
                    </div>
                </a>
            }
            <div class="p-3"> 
                <a asp-controller="Notifications" asp-action="Index">View all</a>
            </div>
        </div>
    </li>
}
else
{
    <li class="nav-item" id="notifications-nav-item">
        <a asp-controller="Notifications" asp-action="Index" title="Notifications" class="nav-link js-scroll-trigger @ViewData.IsActiveCategory(typeof(NotificationsNavPages))" id="Notifications">
            <span class="d-lg-none d-sm-block">Notifications</span><i class="fa fa-bell d-lg-inline-block d-none"></i>
        </a>
    </li>
}
@{
    var disabled = (await SettingsRepository.GetPolicies()).DisableInstantNotifications;
    if (!disabled)
    {
        var user = await UserManager.GetUserAsync(User);
        disabled = user?.DisabledNotifications == "all";
    }
}
@if (!disabled)
{

    <script type="text/javascript">

    var supportsWebSockets = 'WebSocket' in window && window.WebSocket.CLOSING === 2;

    if (supportsWebSockets) {

        var loc = window.location, ws_uri;
        if (loc.protocol === "https:") {
            ws_uri = "wss:";
        } else {
            ws_uri = "ws:";
        }
        ws_uri += "//" + loc.host;
        ws_uri += "@linkGenerator.GetPathByAction("SubscribeUpdates", "Notifications")";
        var newDataEndpoint = "@linkGenerator.GetPathByAction("GetNotificationDropdownUI", "Notifications")";
    
        try {
            socket = new WebSocket(ws_uri);
            socket.onmessage = function (e) {
                $.get(newDataEndpoint, function(data){
                    $("#notifications-nav-item").replaceWith($(data));
               });
            };
            socket.onerror = function (e) {
                console.error("Error while connecting to websocket for notifications (callback)", e);
            };
        }
        catch (e) {
            console.error("Error while connecting to websocket for notifications", e);
        }
    }
    </script>
}


Fixed version (ground truth):
@inject LinkGenerator linkGenerator
@inject UserManager<ApplicationUser> UserManager
@inject ISettingsRepository SettingsRepository
@using BTCPayServer.HostedServices
@using BTCPayServer.Views.Notifications
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Abstractions.Contracts
@using BTCPayServer.Client
@using BTCPayServer.Services
@model BTCPayServer.Components.NotificationsDropdown.NotificationSummaryViewModel
@addTagHelper *, BundlerMinifier.TagHelpers

@if (Model.UnseenCount > 0)
{
    <li class="nav-item dropdown" id="notifications-nav-item">
        <a class="nav-link js-scroll-trigger @ViewData.IsActiveCategory(typeof(NotificationsNavPages))" href="#" id="NotificationsDropdownToggle" role="button" data-bs-toggle="dropdown">
            <span class="d-inline-block d-lg-none">Notifications</span>
            <i class="fa fa-bell d-lg-inline-block d-none"></i>
            <span class="notification-badge badge rounded-pill bg-danger">@Model.UnseenCount</span>
        </a>
        <div class="dropdown-menu dropdown-menu-end text-center notification-dropdown" aria-labelledby="NotificationsDropdownToggle">
            <div class="d-flex align-items-center justify-content-between py-3 px-4 border-bottom border-light"> 
                <h5 class="m-0">Notifications</h5>
                <form id="notificationsForm" asp-controller="Notifications" asp-action="MarkAllAsSeen" asp-route-returnUrl="@Context.Request.GetCurrentPathWithQueryString()" method="post">
                    <button class="btn btn-link p-0" type="submit">Mark all as seen</button>
                </form>
            </div>
            @foreach (var notif in Model.Last5)
            {
                <a asp-action="NotificationPassThrough" asp-controller="Notifications" asp-route-id="@notif.Id" class="notification d-flex align-items-center dropdown-item border-bottom border-light py-3 px-4">
                    <div class="me-3">
                        <vc:icon symbol="note" />
                    </div>

                    <div class="notification-item__content">
                        <div class="text-start text-wrap">
                            @notif.Body
                        </div>
                        <div class="text-start d-flex">
                            <small class="text-muted" data-timeago-unixms="@notif.Created.ToUnixTimeMilliseconds()">@notif.Created.ToTimeAgo()</small>
                        </div>
                    </div>
                </a>
            }
            <div class="p-3"> 
                <a asp-controller="Notifications" asp-action="Index">View all</a>
            </div>
        </div>
    </li>
}
else
{
    <li class="nav-item" id="notifications-nav-item">
        <a asp-controller="Notifications" asp-action="Index" title="Notifications" class="nav-link js-scroll-trigger @ViewData.IsActiveCategory(typeof(NotificationsNavPages))" id="Notifications">
            <span class="d-lg-none d-sm-block">Notifications</span><i class="fa fa-bell d-lg-inline-block d-none"></i>
        </a>
    </li>
}
@{
    var disabled = (await SettingsRepository.GetPolicies()).DisableInstantNotifications;
    if (!disabled)
    {
        var user = await UserManager.GetUserAsync(User);
        disabled = user?.DisabledNotifications == "all";
    }
}
@if (!disabled)
{

    <script type="text/javascript" csp-sha256>

    var supportsWebSockets = 'WebSocket' in window && window.WebSocket.CLOSING === 2;

    if (supportsWebSockets) {

        var loc = window.location, ws_uri;
        if (loc.protocol === "https:") {
            ws_uri = "wss:";
        } else {
            ws_uri = "ws:";
        }
        ws_uri += "//" + loc.host;
        ws_uri += "@linkGenerator.GetPathByAction("SubscribeUpdates", "Notifications")";
        var newDataEndpoint = "@linkGenerator.GetPathByAction("GetNotificationDropdownUI", "Notifications")";
    
        try {
            socket = new WebSocket(ws_uri);
            socket.onmessage = function (e) {
                $.get(newDataEndpoint, function(data){
                    $("#notifications-nav-item").replaceWith($(data));
               });
            };
            socket.onerror = function (e) {
                console.error("Error while connecting to websocket for notifications (callback)", e);
            };
        }
        catch (e) {
            console.error("Error while connecting to websocket for notifications", e);
        }
    }
    </script>
}