[net] html: properly handle trailing solidus in unquoted attribute value in foreign content

67 views
Skip to first unread message

Gopher Robot (Gerrit)

unread,
Mar 27, 2025, 3:33:58 PM3/27/25
to goph...@pubsubhelper.golang.org, Roland Shoemaker, golang-co...@googlegroups.com

Gopher Robot has uploaded the change for review

Commit message

html: properly handle trailing solidus in unquoted attribute value in foreign content

The parser properly treats tags like <p a=/> as <p a="/">, but the
tokenizer emits the SelfClosingTagToken token incorrectly. When the
parser is used to parse foreign content, this results in an incorrect
DOM.

Thanks to Sean Ng (https://ensy.zip) for reporting this issue.

Fixes golang/go#73070
Fixes CVE-2025-22872
Change-Id: I65c18df6d6244bf943b61e6c7a87895929e78f4f

Change diff

diff --git a/html/token.go b/html/token.go
index 3c57880..6598c1f 100644
--- a/html/token.go
+++ b/html/token.go
@@ -839,8 +839,22 @@
if raw {
z.rawTag = strings.ToLower(string(z.buf[z.data.start:z.data.end]))
}
- // Look for a self-closing token like "<br/>".
- if z.err == nil && z.buf[z.raw.end-2] == '/' {
+ // Look for a self-closing token (e.g. <br/>).
+ //
+ // Originally, we did this by just checking that the last character of the
+ // tag (ignoring the closing bracket) was a solidus (/) character, but this
+ // is not always accurate.
+ //
+ // We need to be careful that we don't misinterpret a non-self-closing tag
+ // as self-closing, as can happen if the tag contains unquoted attribute
+ // values (i.e. <p a=/>).
+ //
+ // To avoid this, we check that the last non-bracket character of the tag
+ // (z.raw.end-2) isn't the same character as the last non-quote character of
+ // the last attribute of the tag (z.pendingAttr[1].end-1), if the tag has
+ // attributes.
+ nAttrs := len(z.attr)
+ if z.err == nil && z.buf[z.raw.end-2] == '/' && (nAttrs == 0 || z.raw.end-2 != z.attr[nAttrs-1][1].end-1) {
return SelfClosingTagToken
}
return StartTagToken
diff --git a/html/token_test.go b/html/token_test.go
index a36d112..44773f1 100644
--- a/html/token_test.go
+++ b/html/token_test.go
@@ -616,6 +616,16 @@
`<p a/ ="">`,
`<p a="" =""="">`,
},
+ {
+ "slash at end of unquoted attribute value",
+ `<p a="\">`,
+ `<p a="\">`,
+ },
+ {
+ "self-closing tag with attribute",
+ `<p a=/>`,
+ `<p a="/">`,
+ },
}

func TestTokenizer(t *testing.T) {
@@ -815,6 +825,14 @@
}
}

+func TestSelfClosingTagValueConfusion(t *testing.T) {
+ z := NewTokenizer(strings.NewReader(`<p a=/>`))
+ tok := z.Next()
+ if tok != StartTagToken {
+ t.Fatalf("unexpected token type: got %s, want %s", tok, StartTagToken)
+ }
+}
+
// zeroOneByteReader is like a strings.Reader that alternates between
// returning 0 bytes and 1 byte at a time.
type zeroOneByteReader struct {

Change information

Files:
  • M html/token.go
  • M html/token_test.go
Change size: S
Delta: 2 files changed, 34 insertions(+), 2 deletions(-)
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newchange
Gerrit-Project: net
Gerrit-Branch: master
Gerrit-Change-Id: I65c18df6d6244bf943b61e6c7a87895929e78f4f
Gerrit-Change-Number: 661256
Gerrit-PatchSet: 1
Gerrit-Owner: Gopher Robot <go...@golang.org>
Gerrit-Reviewer: Gopher Robot <go...@golang.org>
Gerrit-CC: Roland Shoemaker <rol...@golang.org>
unsatisfied_requirement
satisfied_requirement
open
diffy

Neal Patel (Gerrit)

unread,
Mar 27, 2025, 3:34:40 PM3/27/25
to Gopher Robot, Roland Shoemaker, goph...@pubsubhelper.golang.org, Go LUCI, golang-co...@googlegroups.com

Neal Patel voted Code-Review+2

Code-Review+2
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: net
Gerrit-Branch: master
Gerrit-Change-Id: I65c18df6d6244bf943b61e6c7a87895929e78f4f
Gerrit-Change-Number: 661256
Gerrit-PatchSet: 1
Gerrit-Owner: Gopher Robot <go...@golang.org>
Gerrit-Reviewer: Gopher Robot <go...@golang.org>
Gerrit-Reviewer: Neal Patel <neal...@google.com>
Gerrit-CC: Roland Shoemaker <rol...@golang.org>
Gerrit-Comment-Date: Thu, 27 Mar 2025 19:34:36 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
satisfied_requirement
unsatisfied_requirement
open
diffy

Roland Shoemaker (Gerrit)

unread,
Mar 27, 2025, 3:51:00 PM3/27/25
to Gopher Robot, goph...@pubsubhelper.golang.org, Go LUCI, Neal Patel, golang-co...@googlegroups.com

Roland Shoemaker voted Code-Review+1

Code-Review+1
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
    • requirement satisfiedCode-Review
    • requirement satisfiedNo-Unresolved-Comments
    • requirement satisfiedReview-Enforcement
    • requirement satisfiedTryBots-Pass
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: net
    Gerrit-Branch: master
    Gerrit-Change-Id: I65c18df6d6244bf943b61e6c7a87895929e78f4f
    Gerrit-Change-Number: 661256
    Gerrit-PatchSet: 1
    Gerrit-Owner: Gopher Robot <go...@golang.org>
    Gerrit-Reviewer: Gopher Robot <go...@golang.org>
    Gerrit-Reviewer: Neal Patel <neal...@google.com>
    Gerrit-Reviewer: Roland Shoemaker <rol...@golang.org>
    Gerrit-Comment-Date: Thu, 27 Mar 2025 19:50:57 +0000
    Gerrit-HasComments: No
    Gerrit-Has-Labels: Yes
    satisfied_requirement
    open
    diffy

    Gopher Robot (Gerrit)

    unread,
    Mar 27, 2025, 3:51:30 PM3/27/25
    to Roland Shoemaker, goph...@pubsubhelper.golang.org, golang-...@googlegroups.com, Go LUCI, Neal Patel, golang-co...@googlegroups.com

    Gopher Robot submitted the change

    Change information

    Commit message:
    html: properly handle trailing solidus in unquoted attribute value in foreign content

    The parser properly treats tags like <p a=/> as <p a="/">, but the
    tokenizer emits the SelfClosingTagToken token incorrectly. When the
    parser is used to parse foreign content, this results in an incorrect
    DOM.

    Thanks to Sean Ng (https://ensy.zip) for reporting this issue.

    Fixes golang/go#73070
    Fixes CVE-2025-22872
    Change-Id: I65c18df6d6244bf943b61e6c7a87895929e78f4f
    Reviewed-by: Neal Patel <neal...@google.com>
    Reviewed-by: Roland Shoemaker <rol...@golang.org>
    Auto-Submit: Gopher Robot <go...@golang.org>
    Files:
    • M html/token.go
    • M html/token_test.go
    Change size: S
    Delta: 2 files changed, 34 insertions(+), 2 deletions(-)
    Branch: refs/heads/master
    Submit Requirements:
    • requirement satisfiedCode-Review: +1 by Roland Shoemaker, +2 by Neal Patel
    • requirement satisfiedTryBots-Pass: LUCI-TryBot-Result+1 by Go LUCI
    Open in Gerrit
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: merged
    Gerrit-Project: net
    Gerrit-Branch: master
    Gerrit-Change-Id: I65c18df6d6244bf943b61e6c7a87895929e78f4f
    Gerrit-Change-Number: 661256
    Gerrit-PatchSet: 2
    open
    diffy
    satisfied_requirement
    Reply all
    Reply to author
    Forward
    0 new messages