Skip to content

Commit 459b9ff

Browse files
felickzCopilot
andcommitted
Address CCR: don't claim guaranteed downstream encoding
Copilot Code Review correctly pointed out that bracketing between BeginWriteTagHelperAttribute()/EndWriteTagHelperAttribute() only proves the value is captured into a buffer rather than written directly to the response; it does not, by itself, guarantee that every tag helper later HTML-attribute-encodes that buffer. Reworded the doc comments and the change note to justify the exclusion on "not a direct write to the response" rather than on assumed downstream encoding. No logic change; XSS.ql compiles and the CWE-079/XSS test still passes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 6a272fb commit 459b9ff

2 files changed

Lines changed: 7 additions & 7 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
---
22
category: majorAnalysis
33
---
4-
* Fixed a false positive in `cs/web/xss` for ASP.NET Core Razor Pages/MVC views: `WriteLiteral` calls generated for tag helper attribute values (for example, `asp-for`) are HTML-attribute-encoded before being rendered, so they are no longer treated as XSS sinks.
4+
* Fixed a false positive in `cs/web/xss` for ASP.NET Core Razor Pages/MVC views: `WriteLiteral` calls generated for tag helper attribute values (for example, `asp-for`) capture the value into an internal buffer instead of writing it directly to the response, so they are no longer treated as XSS sinks.

‎csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/Html.qll‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,10 @@ class MicrosoftAspNetCoreMvcHtmlHelperRawSink extends AspNetCoreHtmlSink {
184184
*
185185
* The Razor source generator emits this bracketing for every literal or expression segment of an
186186
* HTML attribute value on an element that also carries a tag helper (for example `asp-for`). Such
187-
* a `WriteLiteral` call does not write directly, unencoded, to the response: `WriteLiteral`
188-
* appends to an internal string buffer, `EndWriteTagHelperAttribute()` returns that buffer, and
189-
* the buffered text is subsequently stored as a tag helper attribute value and HTML-attribute-
190-
* encoded when the tag helper's output is rendered. This is therefore not a real sink.
187+
* a `WriteLiteral` call does not write directly to the response: `WriteLiteral` appends to an
188+
* internal string buffer, and `EndWriteTagHelperAttribute()` returns that buffer as a tag helper
189+
* attribute value rather than as page markup. This is therefore not a direct-write sink, unlike an
190+
* unbracketed `WriteLiteral` call, whose argument is written straight to the response.
191191
*
192192
* Because a basic block cannot contain a branch, requiring `beginCall`, `writeLiteral`, and
193193
* `endCall` to appear (in that order) in the same basic block, with no other
@@ -244,8 +244,8 @@ private predicate isBracketedForTagHelperAttribute(Call writeLiteral) {
244244
* a `.cshtml` file.
245245
*
246246
* `WriteLiteral` calls whose argument is captured for a tag helper attribute value (see
247-
* `isBracketedForTagHelperAttribute`) are excluded, since such values are HTML-attribute-encoded
248-
* later and are not written unencoded to the response.
247+
* `isBracketedForTagHelperAttribute`) are excluded, since such calls buffer the value as a tag
248+
* helper attribute rather than writing it directly to the response.
249249
*/
250250
class MicrosoftAspNetRazorPageWriteLiteralSink extends AspNetCoreHtmlSink {
251251
MicrosoftAspNetRazorPageWriteLiteralSink() {

0 commit comments

Comments
 (0)