From ce9e61dbfd5309e4f7fa3e9e44f6223eaa829f23 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Fri, 12 Jun 2026 19:50:12 -0400 Subject: [PATCH 1/2] C#: Add Razor Page handler method parameters as remote flow sources ASP.NET Core Razor Page handler method parameters (OnGet, OnPost, etc.) were not modeled as remote flow sources, causing security queries like SQL injection to miss vulnerabilities in PageModel subclasses. This adds AspNetCorePageHandlerMethodParameter, analogous to the existing AspNetCoreActionMethodParameter for MVC controllers, using the existing PageModelClass.getAHandlerMethod() from Razor.qll. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../security/dataflow/flowsources/Remote.qll | 17 +++++++++++ .../aspremote/AspRemoteFlowSource.cs | 28 +++++++++++++++++++ .../aspremote/aspRemoteFlowSource.expected | 7 +++++ 3 files changed, 52 insertions(+) diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll index aa8c8536556e..68c06a1828de 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll @@ -13,6 +13,7 @@ private import semmle.code.csharp.frameworks.system.web.ui.WebControls private import semmle.code.csharp.frameworks.WCF private import semmle.code.csharp.frameworks.microsoft.Owin private import semmle.code.csharp.frameworks.microsoft.AspNetCore +private import semmle.code.csharp.frameworks.Razor private import semmle.code.csharp.dataflow.internal.ExternalFlow private import semmle.code.csharp.security.dataflow.flowsources.FlowSources @@ -314,6 +315,22 @@ class AspNetCoreActionMethodParameter extends AspNetCoreRemoteFlowSource, DataFl override string getSourceType() { result = "ASP.NET Core MVC action method parameter" } } +/** A parameter to a Razor Page handler method, viewed as a source of remote user input. */ +class AspNetCorePageHandlerMethodParameter extends AspNetCoreRemoteFlowSource, + DataFlow::ParameterNode +{ + AspNetCorePageHandlerMethodParameter() { + exists(Parameter p | + p = this.getParameter() and + p.fromSource() + | + p = any(PageModelClass pm).getAHandlerMethod().getAParameter() + ) + } + + override string getSourceType() { result = "ASP.NET Core Razor Page handler method parameter" } +} + private class ExternalRemoteFlowSource extends RemoteFlowSource { ExternalRemoteFlowSource() { sourceNode(this, "remote") } diff --git a/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/AspRemoteFlowSource.cs b/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/AspRemoteFlowSource.cs index e554f25f2064..8507d60cd394 100644 --- a/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/AspRemoteFlowSource.cs +++ b/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/AspRemoteFlowSource.cs @@ -63,4 +63,32 @@ public abstract class AbstractTestController : Controller { public void MyActionMethod(string param) { } } + + // Razor Page handler tests + public class MyPageModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel + { + // BAD: handler method parameters are user-controlled + public void OnGet(string id) { } + + public void OnPost(string command, int count) { } + + public void OnPostAsync(string data) { } + + public void OnPut(string value) { } + + public void OnDelete(string itemId) { } + + // GOOD: not a handler method (doesn't start with On) + public void GetUser(string userId) { } + + // GOOD: marked with NonHandler attribute + [Microsoft.AspNetCore.Mvc.RazorPages.NonHandlerAttribute] + public void OnGetNonHandler(string param) { } + } + + // Subclass of a PageModel subclass + public class DerivedPageModel : MyPageModel + { + public void OnPost(string derivedParam) { } + } } diff --git a/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/aspRemoteFlowSource.expected b/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/aspRemoteFlowSource.expected index d729eb939d28..ef7a8f3cd784 100644 --- a/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/aspRemoteFlowSource.expected +++ b/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/aspRemoteFlowSource.expected @@ -14,3 +14,10 @@ remoteFlowSources | AspRemoteFlowSource.cs:54:69:54:82 | mapDeleteParam | | AspRemoteFlowSource.cs:56:41:56:44 | item | | AspRemoteFlowSource.cs:64:43:64:47 | param | +| AspRemoteFlowSource.cs:71:34:71:35 | id | +| AspRemoteFlowSource.cs:73:35:73:41 | command | +| AspRemoteFlowSource.cs:73:48:73:52 | count | +| AspRemoteFlowSource.cs:75:40:75:43 | data | +| AspRemoteFlowSource.cs:77:34:77:38 | value | +| AspRemoteFlowSource.cs:79:37:79:42 | itemId | +| AspRemoteFlowSource.cs:92:35:92:46 | derivedParam | From 23567eba3db7e45b2b56f94983ff231549b3bc3a Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Fri, 12 Jun 2026 19:53:00 -0400 Subject: [PATCH 2/2] C#: Add change note for Razor Page handler flow sources Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../lib/change-notes/2026-06-12-razor-page-handler-sources.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2026-06-12-razor-page-handler-sources.md diff --git a/csharp/ql/lib/change-notes/2026-06-12-razor-page-handler-sources.md b/csharp/ql/lib/change-notes/2026-06-12-razor-page-handler-sources.md new file mode 100644 index 000000000000..aca9d7631cdf --- /dev/null +++ b/csharp/ql/lib/change-notes/2026-06-12-razor-page-handler-sources.md @@ -0,0 +1,4 @@ +--- +category: majorAnalysis +--- +* Added Razor Page handler method parameters (e.g., `OnGet`, `OnPost`, `OnPostAsync`) as remote flow sources, enabling security queries such as `cs/sql-injection` to detect vulnerabilities in `PageModel` subclasses.