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/3] 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 aa8c8536556..68c06a1828d 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 e554f25f206..8507d60cd39 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 @@ namespace Testing { 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 d729eb939d2..ef7a8f3cd78 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/3] 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 00000000000..aca9d7631cd --- /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. From 4f1d6f472d474e69782c9c3c7902022bc93e5793 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Mon, 15 Jun 2026 11:34:43 -0400 Subject: [PATCH 3/3] Fix test comments: replace GOOD/BAD markers with flow source descriptions Per review feedback, GOOD/BAD markers don't apply to flow source enumeration tests. Use descriptive comments instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../dataflow/flowsources/aspremote/AspRemoteFlowSource.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 8507d60cd39..5bc8025f231 100644 --- a/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/AspRemoteFlowSource.cs +++ b/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/AspRemoteFlowSource.cs @@ -67,7 +67,7 @@ namespace Testing // Razor Page handler tests public class MyPageModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel { - // BAD: handler method parameters are user-controlled + // Handler method parameters are remote flow sources public void OnGet(string id) { } public void OnPost(string command, int count) { } @@ -78,10 +78,10 @@ namespace Testing public void OnDelete(string itemId) { } - // GOOD: not a handler method (doesn't start with On) + // Not a handler method — does not start with "On", so not a flow source public void GetUser(string userId) { } - // GOOD: marked with NonHandler attribute + // Excluded by [NonHandler] attribute, so not a flow source [Microsoft.AspNetCore.Mvc.RazorPages.NonHandlerAttribute] public void OnGetNonHandler(string param) { } }