CVE-2023-1270 (Other, published 2023-03-08T14:15Z)
Description: value: Cross-site Scripting in GitHub repository btcpayserver/btcpayserver prior to 1.8.3.
Severity: nan (CVSS v3 base score: 5.4)
Weakness: CWE-79 \u2014 Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Repository: https://github.com/btcpayserver/btcpayserver
Files changed:
BTCPayServer.Abstractions/Security/ContentSecurityPolicies.cs
BTCPayServer/Filters/ContentSecurityPolicyAttribute.cs
BTCPayServer/Views/Shared/Crowdfund/Public/ViewCrowdfund.cshtml
BTCPayServer/Views/Shared/Crowdfund/UpdateCrowdfund.cshtml
BTCPayServer/Views/Shared/PayButton/PayButton.cshtml
BTCPayServer/Views/Shared/PointOfSale/Public/Light.cshtml
BTCPayServer/Views/Shared/PointOfSale/UpdatePointOfSale.cshtml
BTCPayServer/Views/Shared/PosData.cshtml
BTCPayServer/Views/Shared/TemplateEditor.cshtml
BTCPayServer/Views/Shared/_Layout.cshtml
BTCPayServer/Views/Shared/_LayoutSignedOut.cshtml
BTCPayServer/Views/Shared/_StatusMessage.cshtml
BTCPayServer/Views/Shared/_StoreHeader.cshtml
BTCPayServer/Views/UIAccount/Login.cshtml
BTCPayServer/Views/UICustodianAccounts/ViewCustodianAccount.cshtml
BTCPayServer/Views/UIInvoice/Checkout.cshtml
BTCPayServer/Views/UIInvoice/CheckoutV2.cshtml
BTCPayServer/Views/UIManage/APIKeys.cshtml
BTCPayServer/Views/UIPaymentRequest/ViewPaymentRequest.cshtml
BTCPayServer/Views/UIPullPayment/ViewPullPayment.cshtml
BTCPayServer/Views/UIStores/ImportWallet/Scan.cshtml
BTCPayServer/Views/UIStores/WalletSettings.cshtml
BTCPayServer/Views/UIWallets/WalletPSBT.cshtml
BTCPayServer/Views/UIWallets/WalletPSBTDecoded.cshtml
BTCPayServer/Views/UIWallets/WalletSend.cshtml
Commit message: CSP: Remove unsafe-eval when vue isn't used (#4747)

* CSP: Remove unsafe-eval when vue isn't used

* Prevent XSS injection via VueJS

Vulnerable code:
                ScriptSrc = "'self' 'unsafe-eval'"; // unsafe-eval needed for vue
    ViewData["Title"] = Model.Title;
    Layout = null;
    if (!string.IsNullOrEmpty(Model.DisqusShortname))
    {
        Csp.Add("script-src", $"https://{Model.DisqusShortname}.disqus.com");
        Csp.Add("script-src", "https://c.disquscdn.com");
    }
        <img v-if="srvModel.mainImageUrl" src="@Model.MainImageUrl" :src="srvModel.mainImageUrl" alt="@Model.Title" :alt="srvModel.title" id="crowdfund-main-image" asp-append-version="true"/>
        <h1 class="mb-3">@Model.Title</h1>
            <h2 class="h3 mb-3 fw-semibold" v-if="srvModel.tagline" v-text="srvModel.tagline">@Model.Tagline</h2>
                            @Safe.Raw(Model.Description)
                    @Safe.Raw(Model.Description)
    <noscript>

<table class="table my-0">
                <span class="text-danger">@error.ErrorMessage</span>
<header id="mainMenu" class="btcpay-header d-flex flex-column">
﻿@{
        <h4>@ViewData["Title"]</h4>
    <div class="alert alert-@parsedModel.SeverityCSS @(parsedModel.AllowDismiss? "alert-dismissible":"" ) @(ViewData["Margin"] ?? "mb-4") text-break" role="alert">
<header class="store-header">
    ViewData["Title"] = "Sign in";
    Layout = "_LayoutSignedOut";
    ViewData.SetActivePage(AppsNavPages.Create, "Custodian account: " + @Model?.CustodianAccount.Name);
    Layout = null;
    Layout = null;
    ViewData["Title"] = Model.HtmlTitle;

    var hasPaymentPlugins = UiExtensions.Any(extension => extension.Location == "checkout-payment-method");
                    <h5 class="text-center mt-1 mb-3 fw-semibold" v-if="srvModel.itemDesc" v-text="srvModel.itemDesc">@Model.ItemDesc</h5>
    ViewData.SetActivePage(ManageNavPages.APIKeys, "API Keys");
    ViewData["Title"] = Model.Title;
    Layout = null;
                                <h1 class="h3" v-text="srvModel.title">@Model.Title</h1>
                                <div v-html="srvModel.description">
                                    @Safe.Raw(Model.Description)
                                </div>
    Layout = "_LayoutWalletSetup";
    ViewData.SetActivePage(StoreNavPages.OnchainSettings, "Scan QR code", Context.GetStoreData().Id);
    Layout = "../Shared/_NavLayout.cshtml";
    ViewData["NavPartialName"] = "../UIWallets/_Nav";
    ViewData.SetActivePage(StoreNavPages.OnchainSettings, $"{Model.CryptoCode} Wallet Settings", Context.GetStoreData().Id);
    var walletId = Context.GetRouteValue("walletId").ToString();
    var cancelUrl = Model.ReturnUrl ?? Url.Action(nameof(UIWalletsController.WalletTransactions), new { walletId });
    var backUrl = Model.BackUrl != null ? $"{Model.BackUrl}?returnUrl={Model.ReturnUrl}" : null;
    Layout = "_LayoutWizard";
    ViewData.SetActivePage(WalletsNavPages.PSBT, "Decode PSBT", walletId);
    var cancelUrl = Model.ReturnUrl ?? Url.Action(nameof(UIWalletsController.WalletTransactions), new { walletId });
    var backUrl = Model.BackUrl != null ? $"{Model.BackUrl}?returnUrl={Model.ReturnUrl}" : null;
    var walletId = Context.GetRouteValue("walletId").ToString();
    var cancelUrl = Model.ReturnUrl ?? Url.Action(nameof(UIWalletsController.WalletTransactions), new { walletId });
    var backUrl = Model.BackUrl != null ? $"{Model.BackUrl}?returnUrl={Model.ReturnUrl}" : null;
    Layout = "_LayoutWizard";
    ViewData.SetActivePage(WalletsNavPages.Send, $"Send {Model.CryptoCode}", walletId);
    csp.Add("worker-src", "blob:");

Fixed code:
        public void UnsafeEval()
        {
            Add("script-src", "'unsafe-eval'");
        }

                ScriptSrc = "'self'";
	ViewData["Title"] = Model.Title;
	Layout = null;
	Csp.UnsafeEval();
	if (!string.IsNullOrEmpty(Model.DisqusShortname))
	{
		Csp.Add("script-src", $"https://{Model.DisqusShortname}.disqus.com");
		Csp.Add("script-src", "https://c.disquscdn.com");
	}
        <img v-if="srvModel.mainImageUrl" :src="srvModel.mainImageUrl" :alt="srvModel.title" id="crowdfund-main-image" asp-append-version="true"/>
	  <h1 class="mb-3">{{ srvModel.title }}</h1>
            <h2 class="h3 mb-3 fw-semibold" v-if="srvModel.tagline" v-text="srvModel.tagline"></h2>
	<noscript v-pre>
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	Csp.UnsafeEval();
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	Csp.UnsafeEval();
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	Csp.UnsafeEval();
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	Csp.UnsafeEval();
<table class="table my-0" v-pre>
                <span class="text-danger" v-pre>@error.ErrorMessage</span>
<header id="mainMenu" class="btcpay-header d-flex flex-column" v-pre>
@{
	  <h4 v-pre>@ViewData["Title"]</h4>
	<div class="alert alert-@parsedModel.SeverityCSS @(parsedModel.AllowDismiss? "alert-dismissible":"" ) @(ViewData["Margin"] ?? "mb-4") text-break" role="alert" v-pre>
<header class="store-header" v-pre>
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	ViewData["Title"] = "Sign in";
	Layout = "_LayoutSignedOut";
	Csp.UnsafeEval();
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	ViewData.SetActivePage(AppsNavPages.Create, "Custodian account: " + @Model?.CustodianAccount.Name);
	Csp.UnsafeEval();
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	Layout = null;
	Csp.UnsafeEval();
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	Layout = null;
	ViewData["Title"] = Model.HtmlTitle;
	Csp.UnsafeEval();
	var hasPaymentPlugins = UiExtensions.Any(extension => extension.Location == "checkout-payment-method");
                    <h5 class="text-center mt-1 mb-3 fw-semibold" v-if="srvModel.itemDesc" v-text="srvModel.itemDesc"></h5>
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	ViewData.SetActivePage(ManageNavPages.APIKeys, "API Keys");
	Csp.UnsafeEval();
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	ViewData["Title"] = Model.Title;
	Csp.UnsafeEval();
	Layout = null;
                                <h1 class="h3" v-text="srvModel.title"></h1>
                                <div v-html="srvModel.description"></div>
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	Csp.UnsafeEval();
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	Layout = "_LayoutWalletSetup";
	ViewData.SetActivePage(StoreNavPages.OnchainSettings, "Scan QR code", Context.GetStoreData().Id);
	Csp.UnsafeEval();
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	Layout = "../Shared/_NavLayout.cshtml";
	ViewData["NavPartialName"] = "../UIWallets/_Nav";
	ViewData.SetActivePage(StoreNavPages.OnchainSettings, $"{Model.CryptoCode} Wallet Settings", Context.GetStoreData().Id);
	Csp.UnsafeEval();
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	var walletId = Context.GetRouteValue("walletId").ToString();
	var cancelUrl = Model.ReturnUrl ?? Url.Action(nameof(UIWalletsController.WalletTransactions), new { walletId });
	var backUrl = Model.BackUrl != null ? $"{Model.BackUrl}?returnUrl={Model.ReturnUrl}" : null;
	Layout = "_LayoutWizard";
	ViewData.SetActivePage(WalletsNavPages.PSBT, "Decode PSBT", walletId);
	Csp.UnsafeEval();
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	var cancelUrl = Model.ReturnUrl ?? Url.Action(nameof(UIWalletsController.WalletTransactions), new { walletId });
	var backUrl = Model.BackUrl != null ? $"{Model.BackUrl}?returnUrl={Model.ReturnUrl}" : null;
	Csp.UnsafeEval();
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
	var walletId = Context.GetRouteValue("walletId").ToString();
	var cancelUrl = Model.ReturnUrl ?? Url.Action(nameof(UIWalletsController.WalletTransactions), new { walletId });
	var backUrl = Model.BackUrl != null ? $"{Model.BackUrl}?returnUrl={Model.ReturnUrl}" : null;
	Layout = "_LayoutWizard";
	ViewData.SetActivePage(WalletsNavPages.Send, $"Send {Model.CryptoCode}", walletId);
	csp.Add("worker-src", "blob:");
	Csp.UnsafeEval();