What changed, and why it matters
This commit removes a feature called 'Razor runtime compilation' from the main BTCPay Server application. Previously, in debug/development builds, the server could recompile web page templates (Razor views) on the fly while running. The change makes the server always use pre-compiled views instead. Runtime compilation is useful for developers but can increase attack surface, so removing it from production-like builds is a hardening move. A special test-only flag is added so developers can still enable it for testing.
No immediate action required. Operators building from source should verify that views are pre-compiled during build (RazorCompileOnBuild remains true by default). Reviewers may want to confirm that the test-only runtime compilation path is not reachable in production deployments and that no other code paths re-enable runtime compilation outside the test harness.
Security signals we found
Removal of runtime code compilation feature from default application startup
Reduction of dependency attack surface by dropping Razor.RuntimeCompilation package
Hardening against potential view compilation abuse or file-system watching side channels
Test-only opt-in preserves developer workflow without exposing runtime compiler in default builds
Evidence from the diff
The patch removes conditional Razor runtime compilation from BTCPayServer’s Startup.cs and the associated MSBuild conditions in BTCPayServer.csproj that controlled whether views were compiled at build time or at runtime. The Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation package reference is dropped. A new RuntimeCompilation boolean property is added to BTCPayServerTester so the test harness can opt into runtime compilation explicitly (used by UtilitiesTests.cs), while the production/development default becomes pre-compiled views.
Changed components
BTCPayServer/Hosting/Startup.csBTCPayServer/BTCPayServer.csprojBTCPayServer.Tests/BTCPayServerTester.csBTCPayServer.Tests/UtilitiesTests.csInspect captured patch +4 / −25
diff --git a/BTCPayServer.Tests/BTCPayServerTester.cs b/BTCPayServer.Tests/BTCPayServerTester.cs
index 615bdf4..a106785 100644
--- a/BTCPayServer.Tests/BTCPayServerTester.cs
+++ b/BTCPayServer.Tests/BTCPayServerTester.cs
@@ -10,7 +10,6 @@ using System.Threading.Tasks;
using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Configuration;
-using BTCPayServer.Controllers;
using BTCPayServer.Hosting;
using BTCPayServer.Payments;
using BTCPayServer.Payments.Bitcoin;
@@ -220,6 +219,8 @@ namespace BTCPayServer.Tests
.UseStartup<Startup>()
.ConfigureServices(services =>
{
+ if (RuntimeCompilation)
+ services.AddMvcCore().AddRazorRuntimeCompilation();
services.TryAddSingleton<IFeeProviderFactory>(
new BTCPayServer.Services.Fees.FixedFeeProvider(new FeeRate(100L, 1)));
});
@@ -365,6 +366,7 @@ namespace BTCPayServer.Tests
public string SSHConnection { get; set; }
public bool NoCSP { get; set; }
public string HostEnvironment { get; set; } = Environments.Development;
+ public bool RuntimeCompilation { get; set; }
public T GetController<T>(string userId = null, string storeId = null, bool isAdmin = false) where T : Controller
{
diff --git a/BTCPayServer.Tests/UtilitiesTests.cs b/BTCPayServer.Tests/UtilitiesTests.cs
index f1c02b4..ed5b98b 100644
--- a/BTCPayServer.Tests/UtilitiesTests.cs
+++ b/BTCPayServer.Tests/UtilitiesTests.cs
@@ -15,21 +15,15 @@ using BTCPayServer.Client;
using BTCPayServer.Client.Models;
using BTCPayServer.Controllers;
using BTCPayServer.Services;
-using ExchangeSharp;
-using Microsoft.AspNetCore.Html;
-using Microsoft.AspNetCore.Mvc.Localization;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
-using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.Extensions.FileSystemGlobbing;
using NBitcoin;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit;
using Xunit.Abstractions;
-using static System.Net.Mime.MediaTypeNames;
namespace BTCPayServer.Tests
{
@@ -259,6 +253,7 @@ namespace BTCPayServer.Tests
// Go through all cshtml file, search for text-translate or ViewLocalizer usage
using (var tester = CreateServerTester(newDb: true))
{
+ tester.PayTester.RuntimeCompilation = true;
await tester.StartAsync();
var engine = tester.PayTester.GetService<RazorProjectEngine>();
var files = soldir.EnumerateFiles("*.cshtml", SearchOption.AllDirectories)
diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj
index 9cd8607..b62a849 100644
--- a/BTCPayServer/BTCPayServer.csproj
+++ b/BTCPayServer/BTCPayServer.csproj
@@ -9,18 +9,6 @@
<RunAnalyzersDuringBuild>False</RunAnalyzersDuringBuild>
</PropertyGroup>
- <!-- Pre-compiling views should only be done for Release builds without dotnet watch or design time build .-->
- <!-- Runtime compiling is only useful for debugging with hot reload of the views -->
- <PropertyGroup Condition="'$(RazorCompileOnBuild)'=='' AND ('$(Configuration)' == 'Debug' OR '$(DotNetWatchBuild)' == 'true' OR '$(DesignTimeBuild)' == 'true')">
- <RazorCompileOnBuild>false</RazorCompileOnBuild>
- </PropertyGroup>
- <PropertyGroup Condition="'$(RazorCompileOnBuild)'==''">
- <RazorCompileOnBuild>true</RazorCompileOnBuild>
- </PropertyGroup>
- <PropertyGroup Condition="'$(RazorCompileOnBuild)' == 'true'">
- <DefineConstants>$(DefineConstants);RAZOR_COMPILE_ON_BUILD</DefineConstants>
- </PropertyGroup>
-
<ItemGroup>
<AssemblyAttribute Condition="'$(GitCommit)' != ''" Include="BTCPayServer.GitCommitAttribute">
<_Parameter1>$(GitCommit)</_Parameter1>
@@ -80,7 +68,6 @@
<PackageReference Include="TwentyTwenty.Storage.Azure" Version="2.26.1" />
<PackageReference Include="TwentyTwenty.Storage.Google" Version="2.26.1" />
<PackageReference Include="TwentyTwenty.Storage.Local" Version="2.26.1" />
- <PackageReference Condition="'$(RazorCompileOnBuild)' == 'false'" Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="10.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="10.0.1" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="10.0.1" />
</ItemGroup>
diff --git a/BTCPayServer/Hosting/Startup.cs b/BTCPayServer/Hosting/Startup.cs
index 8ddc0e7..8d1b219 100644
--- a/BTCPayServer/Hosting/Startup.cs
+++ b/BTCPayServer/Hosting/Startup.cs
@@ -193,11 +193,6 @@ namespace BTCPayServer.Hosting
.AddDataAnnotationsLocalization()
.AddControllersAsServices();
-#if !RAZOR_COMPILE_ON_BUILD
- mvcBuilder.AddRazorRuntimeCompilation();
-#endif
-
-
services.AddServerSideBlazor().AddHubOptions(o =>
{
// PSBT with previous transactions could become
Why this scored 26/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.