Low severityOSV Advisory· Published Jan 16, 2026· Updated Jan 16, 2026
DoS from quadratic complexity in model.ParseHashtags
CVE-2025-14822
Description
Mattermost versions 10.11.x <= 10.11.8 fail to validate input size before processing hashtags which allows an authenticated attacker to exhaust CPU resources via a single HTTP request containing a post with thousands space-separated tokens
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/mattermost/mattermost-serverGo | >= 10.11.0, < 10.11.9 | 10.11.9 |
github.com/mattermost/mattermost-serverGo | >= 11.0.0, < 11.2.0 | 11.2.0 |
Affected products
1- Range: @mattermost/client@10.11.0, @mattermost/types@10.11.0, mattermost-redux@10.11.0, …
Patches
2b3d6c0c564c1perf: apply perfpsrint linter (#33967) (#34632)
6 files changed · +131 −60
server/public/model/utils.go+6 −5 modified@@ -717,8 +717,8 @@ var ( func ParseHashtags(text string) (string, string) { words := strings.Fields(text) - hashtagString := "" - plainString := "" + var hashtagStringSb strings.Builder + var plainString strings.Builder for _, word := range words { // trim off surrounding punctuation word = puncStart.ReplaceAllString(word, "") @@ -728,11 +728,12 @@ func ParseHashtags(text string) (string, string) { word = hashtagStart.ReplaceAllString(word, "#") if validHashtag.MatchString(word) { - hashtagString += " " + word + hashtagStringSb.WriteString(" " + word) } else { - plainString += " " + word + plainString.WriteString(" " + word) } } + hashtagString := hashtagStringSb.String() if len(hashtagString) > 1000 { hashtagString = hashtagString[:999] @@ -744,7 +745,7 @@ func ParseHashtags(text string) (string, string) { } } - return strings.TrimSpace(hashtagString), strings.TrimSpace(plainString) + return strings.TrimSpace(hashtagString), strings.TrimSpace(plainString.String()) } func ClearMentionTags(post string) string {
server/public/model/utils_test.go+52 −4 modified@@ -541,10 +541,58 @@ func TestStringArray_Equal(t *testing.T) { } func TestParseHashtags(t *testing.T) { - for input, output := range hashtags { - o, _ := ParseHashtags(input) - require.Equal(t, o, output, "failed to parse hashtags from input="+input+" expected="+output+" actual="+o) - } + t.Run("basic hashtag extraction", func(t *testing.T) { + for input, output := range hashtags { + o, _ := ParseHashtags(input) + require.Equal(t, o, output, "failed to parse hashtags from input="+input+" expected="+output+" actual="+o) + } + }) + + t.Run("long hashtag string truncation", func(t *testing.T) { + // Test case where hashtag string exceeds 1000 characters with a space to truncate at + longHashtags := "#test " + strings.Repeat("#verylonghashtag ", 50) + hashtagString, plainString := ParseHashtags(longHashtags) + require.NotEmpty(t, hashtagString) + require.LessOrEqual(t, len(hashtagString), 1000) + require.Empty(t, plainString) + // Ensure it truncated at a space + require.NotEqual(t, "", hashtagString) + require.True(t, hashtagString[len(hashtagString)-1] != ' ') + }) + + t.Run("long hashtag string truncation without spaces", func(t *testing.T) { + // Test case where hashtag string exceeds 1000 characters with no space after position 999 + // Create a single very long hashtag that will be truncated + veryLongHashtag := "#" + strings.Repeat("a", 1010) + hashtagString, plainString := ParseHashtags(veryLongHashtag) + // Should be empty because no space was found to truncate at + require.Equal(t, "", hashtagString) + require.Empty(t, plainString) + }) + + t.Run("plain text extraction", func(t *testing.T) { + hashtagString, plainString := ParseHashtags("hello #world this is #test plain text") + require.Equal(t, "#world #test", hashtagString) + require.Equal(t, "hello this is plain text", plainString) + }) + + t.Run("only plain text", func(t *testing.T) { + hashtagString, plainString := ParseHashtags("no hashtags here") + require.Empty(t, hashtagString) + require.Equal(t, "no hashtags here", plainString) + }) + + t.Run("only hashtags", func(t *testing.T) { + hashtagString, plainString := ParseHashtags("#one #two #three") + require.Equal(t, "#one #two #three", hashtagString) + require.Empty(t, plainString) + }) + + t.Run("empty string", func(t *testing.T) { + hashtagString, plainString := ParseHashtags("") + require.Empty(t, hashtagString) + require.Empty(t, plainString) + }) } func TestIsValidAlphaNum(t *testing.T) {
server/public/shared/markdown/fenced_code.go+4 −3 modified@@ -23,11 +23,12 @@ type FencedCode struct { RawCode []FencedCodeLine } -func (b *FencedCode) Code() (result string) { +func (b *FencedCode) Code() string { + var resultSb strings.Builder for _, code := range b.RawCode { - result += strings.Repeat(" ", code.Indentation) + b.markdown[code.Range.Position:code.Range.End] + resultSb.WriteString(strings.Repeat(" ", code.Indentation) + b.markdown[code.Range.Position:code.Range.End]) } - return + return resultSb.String() } func (b *FencedCode) Info() string {
server/public/shared/markdown/html.go+60 −43 modified@@ -27,69 +27,75 @@ func RenderBlockHTML(block Block, referenceDefinitions []*ReferenceDefinition) ( return renderBlockHTML(block, referenceDefinitions, false) } -func renderBlockHTML(block Block, referenceDefinitions []*ReferenceDefinition, isTightList bool) (result string) { +func renderBlockHTML(block Block, referenceDefinitions []*ReferenceDefinition, isTightList bool) string { + var resultSb strings.Builder + switch v := block.(type) { case *Document: for _, block := range v.Children { - result += RenderBlockHTML(block, referenceDefinitions) + resultSb.WriteString(RenderBlockHTML(block, referenceDefinitions)) } case *Paragraph: if len(v.Text) == 0 { - return + return "" } if !isTightList { - result += "<p>" + resultSb.WriteString("<p>") } for _, inline := range v.ParseInlines(referenceDefinitions) { - result += RenderInlineHTML(inline) + resultSb.WriteString(RenderInlineHTML(inline)) } if !isTightList { - result += "</p>" + resultSb.WriteString("</p>") } case *List: if v.IsOrdered { if v.OrderedStart != 1 { - result += fmt.Sprintf(`<ol start="%v">`, v.OrderedStart) + resultSb.WriteString(fmt.Sprintf(`<ol start="%v">`, v.OrderedStart)) } else { - result += "<ol>" + resultSb.WriteString("<ol>") } } else { - result += "<ul>" + resultSb.WriteString("<ul>") } for _, block := range v.Children { - result += renderBlockHTML(block, referenceDefinitions, !v.IsLoose) + resultSb.WriteString(renderBlockHTML(block, referenceDefinitions, !v.IsLoose)) } if v.IsOrdered { - result += "</ol>" + resultSb.WriteString("</ol>") } else { - result += "</ul>" + resultSb.WriteString("</ul>") } case *ListItem: - result += "<li>" + resultSb.WriteString("<li>") for _, block := range v.Children { - result += renderBlockHTML(block, referenceDefinitions, isTightList) + resultSb.WriteString(renderBlockHTML(block, referenceDefinitions, isTightList)) } - result += "</li>" + resultSb.WriteString("</li>") case *BlockQuote: - result += "<blockquote>" + resultSb.WriteString("<blockquote>") for _, block := range v.Children { - result += RenderBlockHTML(block, referenceDefinitions) + resultSb.WriteString(RenderBlockHTML(block, referenceDefinitions)) } - result += "</blockquote>" + resultSb.WriteString("</blockquote>") case *FencedCode: if info := v.Info(); info != "" { language := strings.Fields(info)[0] - result += `<pre><code class="language-` + htmlEscaper.Replace(language) + `">` + resultSb.WriteString(`<pre><code class="language-` + htmlEscaper.Replace(language) + `">`) } else { - result += "<pre><code>" + resultSb.WriteString("<pre><code>") } - result += htmlEscaper.Replace(v.Code()) + "</code></pre>" + resultSb.WriteString(htmlEscaper.Replace(v.Code())) + resultSb.WriteString("</code></pre>") case *IndentedCode: - result += "<pre><code>" + htmlEscaper.Replace(v.Code()) + "</code></pre>" + resultSb.WriteString("<pre><code>") + resultSb.WriteString(htmlEscaper.Replace(v.Code())) + resultSb.WriteString("</code></pre>") default: panic(fmt.Sprintf("missing case for type %T", v)) } - return + + return resultSb.String() } func escapeURL(url string) (result string) { @@ -137,31 +143,37 @@ func RenderInlineHTML(inline Inline) (result string) { } result += ` />` case *InlineLink: - result += `<a href="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `"` + var resultSb strings.Builder + resultSb.WriteString(`<a href="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `"`) if title := v.Title(); title != "" { - result += ` title="` + htmlEscaper.Replace(title) + `"` + resultSb.WriteString(` title="` + htmlEscaper.Replace(title) + `"`) } - result += `>` + resultSb.WriteString(`>`) for _, inline := range v.Children { - result += RenderInlineHTML(inline) + resultSb.WriteString(RenderInlineHTML(inline)) } - result += "</a>" + resultSb.WriteString("</a>") + return resultSb.String() case *ReferenceLink: - result += `<a href="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `"` + var resultSb strings.Builder + resultSb.WriteString(`<a href="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `"`) if title := v.Title(); title != "" { - result += ` title="` + htmlEscaper.Replace(title) + `"` + resultSb.WriteString(` title="` + htmlEscaper.Replace(title) + `"`) } - result += `>` + resultSb.WriteString(`>`) for _, inline := range v.Children { - result += RenderInlineHTML(inline) + resultSb.WriteString(RenderInlineHTML(inline)) } - result += "</a>" + resultSb.WriteString("</a>") + return resultSb.String() case *Autolink: - result += `<a href="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `">` + var resultSb strings.Builder + resultSb.WriteString(`<a href="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `">`) for _, inline := range v.Children { - result += RenderInlineHTML(inline) + resultSb.WriteString(RenderInlineHTML(inline)) } - result += "</a>" + resultSb.WriteString("</a>") + return resultSb.String() case *Emoji: escapedName := htmlEscaper.Replace(v.Name) result += fmt.Sprintf(`<span data-emoji-name="%s" data-literal=":%s:" />`, escapedName, escapedName) @@ -172,25 +184,30 @@ func RenderInlineHTML(inline Inline) (result string) { return } -func renderImageAltText(children []Inline) (result string) { +func renderImageAltText(children []Inline) string { + var resultSb strings.Builder for _, inline := range children { - result += renderImageChildAltText(inline) + resultSb.WriteString(renderImageChildAltText(inline)) } - return + return resultSb.String() } -func renderImageChildAltText(inline Inline) (result string) { +func renderImageChildAltText(inline Inline) string { switch v := inline.(type) { case *Text: return v.Text case *InlineImage: + var resultSb strings.Builder for _, inline := range v.Children { - result += renderImageChildAltText(inline) + resultSb.WriteString(renderImageChildAltText(inline)) } + return resultSb.String() case *InlineLink: + var resultSb strings.Builder for _, inline := range v.Children { - result += renderImageChildAltText(inline) + resultSb.WriteString(renderImageChildAltText(inline)) } + return resultSb.String() } - return + return "" }
server/public/shared/markdown/indented_code.go+4 −3 modified@@ -19,11 +19,12 @@ type IndentedCode struct { RawCode []IndentedCodeLine } -func (b *IndentedCode) Code() (result string) { +func (b *IndentedCode) Code() string { + var resultSb strings.Builder for _, code := range b.RawCode { - result += strings.Repeat(" ", code.Indentation) + b.markdown[code.Range.Position:code.Range.End] + resultSb.WriteString(strings.Repeat(" ", code.Indentation) + b.markdown[code.Range.Position:code.Range.End]) } - return + return resultSb.String() } func (b *IndentedCode) Continuation(indentation int, r Range) *continuation {
server/public/shared/markdown/reference_definition.go+5 −2 modified@@ -3,6 +3,8 @@ package markdown +import "strings" + type ReferenceDefinition struct { RawDestination Range @@ -24,10 +26,11 @@ func (d *ReferenceDefinition) Title() string { } func parseReferenceDefinition(markdown string, ranges []Range) (*ReferenceDefinition, []Range) { - raw := "" + var rawSb strings.Builder for _, r := range ranges { - raw += markdown[r.Position:r.End] + rawSb.WriteString(markdown[r.Position:r.End]) } + raw := rawSb.String() label, next, ok := parseLinkLabel(raw, 0) if !ok {
4d86263f5430perf: apply perfpsrint linter (#33967) (#34619)
6 files changed · +128 −57
server/public/model/utils.go+3 −2 modified@@ -712,7 +712,7 @@ var ( func ParseHashtags(text string) (string, string) { words := strings.Fields(text) - hashtagString := "" + var hashtagStringSb strings.Builder var plainString strings.Builder for _, word := range words { // trim off surrounding punctuation @@ -723,11 +723,12 @@ func ParseHashtags(text string) (string, string) { word = hashtagStart.ReplaceAllString(word, "#") if validHashtag.MatchString(word) { - hashtagString += " " + word + hashtagStringSb.WriteString(" " + word) } else { plainString.WriteString(" " + word) } } + hashtagString := hashtagStringSb.String() if len(hashtagString) > 1000 { hashtagString = hashtagString[:999]
server/public/model/utils_test.go+52 −4 modified@@ -541,10 +541,58 @@ func TestStringArray_Equal(t *testing.T) { } func TestParseHashtags(t *testing.T) { - for input, output := range hashtags { - o, _ := ParseHashtags(input) - require.Equal(t, o, output, "failed to parse hashtags from input="+input+" expected="+output+" actual="+o) - } + t.Run("basic hashtag extraction", func(t *testing.T) { + for input, output := range hashtags { + o, _ := ParseHashtags(input) + require.Equal(t, o, output, "failed to parse hashtags from input="+input+" expected="+output+" actual="+o) + } + }) + + t.Run("long hashtag string truncation", func(t *testing.T) { + // Test case where hashtag string exceeds 1000 characters with a space to truncate at + longHashtags := "#test " + strings.Repeat("#verylonghashtag ", 50) + hashtagString, plainString := ParseHashtags(longHashtags) + require.NotEmpty(t, hashtagString) + require.LessOrEqual(t, len(hashtagString), 1000) + require.Empty(t, plainString) + // Ensure it truncated at a space + require.NotEqual(t, "", hashtagString) + require.True(t, hashtagString[len(hashtagString)-1] != ' ') + }) + + t.Run("long hashtag string truncation without spaces", func(t *testing.T) { + // Test case where hashtag string exceeds 1000 characters with no space after position 999 + // Create a single very long hashtag that will be truncated + veryLongHashtag := "#" + strings.Repeat("a", 1010) + hashtagString, plainString := ParseHashtags(veryLongHashtag) + // Should be empty because no space was found to truncate at + require.Equal(t, "", hashtagString) + require.Empty(t, plainString) + }) + + t.Run("plain text extraction", func(t *testing.T) { + hashtagString, plainString := ParseHashtags("hello #world this is #test plain text") + require.Equal(t, "#world #test", hashtagString) + require.Equal(t, "hello this is plain text", plainString) + }) + + t.Run("only plain text", func(t *testing.T) { + hashtagString, plainString := ParseHashtags("no hashtags here") + require.Empty(t, hashtagString) + require.Equal(t, "no hashtags here", plainString) + }) + + t.Run("only hashtags", func(t *testing.T) { + hashtagString, plainString := ParseHashtags("#one #two #three") + require.Equal(t, "#one #two #three", hashtagString) + require.Empty(t, plainString) + }) + + t.Run("empty string", func(t *testing.T) { + hashtagString, plainString := ParseHashtags("") + require.Empty(t, hashtagString) + require.Empty(t, plainString) + }) } func TestIsValidAlphaNum(t *testing.T) {
server/public/shared/markdown/fenced_code.go+4 −3 modified@@ -23,11 +23,12 @@ type FencedCode struct { RawCode []FencedCodeLine } -func (b *FencedCode) Code() (result string) { +func (b *FencedCode) Code() string { + var resultSb strings.Builder for _, code := range b.RawCode { - result += strings.Repeat(" ", code.Indentation) + b.markdown[code.Range.Position:code.Range.End] + resultSb.WriteString(strings.Repeat(" ", code.Indentation) + b.markdown[code.Range.Position:code.Range.End]) } - return + return resultSb.String() } func (b *FencedCode) Info() string {
server/public/shared/markdown/html.go+60 −43 modified@@ -27,69 +27,75 @@ func RenderBlockHTML(block Block, referenceDefinitions []*ReferenceDefinition) ( return renderBlockHTML(block, referenceDefinitions, false) } -func renderBlockHTML(block Block, referenceDefinitions []*ReferenceDefinition, isTightList bool) (result string) { +func renderBlockHTML(block Block, referenceDefinitions []*ReferenceDefinition, isTightList bool) string { + var resultSb strings.Builder + switch v := block.(type) { case *Document: for _, block := range v.Children { - result += RenderBlockHTML(block, referenceDefinitions) + resultSb.WriteString(RenderBlockHTML(block, referenceDefinitions)) } case *Paragraph: if len(v.Text) == 0 { - return + return "" } if !isTightList { - result += "<p>" + resultSb.WriteString("<p>") } for _, inline := range v.ParseInlines(referenceDefinitions) { - result += RenderInlineHTML(inline) + resultSb.WriteString(RenderInlineHTML(inline)) } if !isTightList { - result += "</p>" + resultSb.WriteString("</p>") } case *List: if v.IsOrdered { if v.OrderedStart != 1 { - result += fmt.Sprintf(`<ol start="%v">`, v.OrderedStart) + resultSb.WriteString(fmt.Sprintf(`<ol start="%v">`, v.OrderedStart)) } else { - result += "<ol>" + resultSb.WriteString("<ol>") } } else { - result += "<ul>" + resultSb.WriteString("<ul>") } for _, block := range v.Children { - result += renderBlockHTML(block, referenceDefinitions, !v.IsLoose) + resultSb.WriteString(renderBlockHTML(block, referenceDefinitions, !v.IsLoose)) } if v.IsOrdered { - result += "</ol>" + resultSb.WriteString("</ol>") } else { - result += "</ul>" + resultSb.WriteString("</ul>") } case *ListItem: - result += "<li>" + resultSb.WriteString("<li>") for _, block := range v.Children { - result += renderBlockHTML(block, referenceDefinitions, isTightList) + resultSb.WriteString(renderBlockHTML(block, referenceDefinitions, isTightList)) } - result += "</li>" + resultSb.WriteString("</li>") case *BlockQuote: - result += "<blockquote>" + resultSb.WriteString("<blockquote>") for _, block := range v.Children { - result += RenderBlockHTML(block, referenceDefinitions) + resultSb.WriteString(RenderBlockHTML(block, referenceDefinitions)) } - result += "</blockquote>" + resultSb.WriteString("</blockquote>") case *FencedCode: if info := v.Info(); info != "" { language := strings.Fields(info)[0] - result += `<pre><code class="language-` + htmlEscaper.Replace(language) + `">` + resultSb.WriteString(`<pre><code class="language-` + htmlEscaper.Replace(language) + `">`) } else { - result += "<pre><code>" + resultSb.WriteString("<pre><code>") } - result += htmlEscaper.Replace(v.Code()) + "</code></pre>" + resultSb.WriteString(htmlEscaper.Replace(v.Code())) + resultSb.WriteString("</code></pre>") case *IndentedCode: - result += "<pre><code>" + htmlEscaper.Replace(v.Code()) + "</code></pre>" + resultSb.WriteString("<pre><code>") + resultSb.WriteString(htmlEscaper.Replace(v.Code())) + resultSb.WriteString("</code></pre>") default: panic(fmt.Sprintf("missing case for type %T", v)) } - return + + return resultSb.String() } func escapeURL(url string) (result string) { @@ -137,31 +143,37 @@ func RenderInlineHTML(inline Inline) (result string) { } result += ` />` case *InlineLink: - result += `<a href="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `"` + var resultSb strings.Builder + resultSb.WriteString(`<a href="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `"`) if title := v.Title(); title != "" { - result += ` title="` + htmlEscaper.Replace(title) + `"` + resultSb.WriteString(` title="` + htmlEscaper.Replace(title) + `"`) } - result += `>` + resultSb.WriteString(`>`) for _, inline := range v.Children { - result += RenderInlineHTML(inline) + resultSb.WriteString(RenderInlineHTML(inline)) } - result += "</a>" + resultSb.WriteString("</a>") + return resultSb.String() case *ReferenceLink: - result += `<a href="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `"` + var resultSb strings.Builder + resultSb.WriteString(`<a href="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `"`) if title := v.Title(); title != "" { - result += ` title="` + htmlEscaper.Replace(title) + `"` + resultSb.WriteString(` title="` + htmlEscaper.Replace(title) + `"`) } - result += `>` + resultSb.WriteString(`>`) for _, inline := range v.Children { - result += RenderInlineHTML(inline) + resultSb.WriteString(RenderInlineHTML(inline)) } - result += "</a>" + resultSb.WriteString("</a>") + return resultSb.String() case *Autolink: - result += `<a href="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `">` + var resultSb strings.Builder + resultSb.WriteString(`<a href="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `">`) for _, inline := range v.Children { - result += RenderInlineHTML(inline) + resultSb.WriteString(RenderInlineHTML(inline)) } - result += "</a>" + resultSb.WriteString("</a>") + return resultSb.String() case *Emoji: escapedName := htmlEscaper.Replace(v.Name) result += fmt.Sprintf(`<span data-emoji-name="%s" data-literal=":%s:" />`, escapedName, escapedName) @@ -172,25 +184,30 @@ func RenderInlineHTML(inline Inline) (result string) { return } -func renderImageAltText(children []Inline) (result string) { +func renderImageAltText(children []Inline) string { + var resultSb strings.Builder for _, inline := range children { - result += renderImageChildAltText(inline) + resultSb.WriteString(renderImageChildAltText(inline)) } - return + return resultSb.String() } -func renderImageChildAltText(inline Inline) (result string) { +func renderImageChildAltText(inline Inline) string { switch v := inline.(type) { case *Text: return v.Text case *InlineImage: + var resultSb strings.Builder for _, inline := range v.Children { - result += renderImageChildAltText(inline) + resultSb.WriteString(renderImageChildAltText(inline)) } + return resultSb.String() case *InlineLink: + var resultSb strings.Builder for _, inline := range v.Children { - result += renderImageChildAltText(inline) + resultSb.WriteString(renderImageChildAltText(inline)) } + return resultSb.String() } - return + return "" }
server/public/shared/markdown/indented_code.go+4 −3 modified@@ -19,11 +19,12 @@ type IndentedCode struct { RawCode []IndentedCodeLine } -func (b *IndentedCode) Code() (result string) { +func (b *IndentedCode) Code() string { + var resultSb strings.Builder for _, code := range b.RawCode { - result += strings.Repeat(" ", code.Indentation) + b.markdown[code.Range.Position:code.Range.End] + resultSb.WriteString(strings.Repeat(" ", code.Indentation) + b.markdown[code.Range.Position:code.Range.End]) } - return + return resultSb.String() } func (b *IndentedCode) Continuation(indentation int, r Range) *continuation {
server/public/shared/markdown/reference_definition.go+5 −2 modified@@ -3,6 +3,8 @@ package markdown +import "strings" + type ReferenceDefinition struct { RawDestination Range @@ -24,10 +26,11 @@ func (d *ReferenceDefinition) Title() string { } func parseReferenceDefinition(markdown string, ranges []Range) (*ReferenceDefinition, []Range) { - raw := "" + var rawSb strings.Builder for _, r := range ranges { - raw += markdown[r.Position:r.End] + rawSb.WriteString(markdown[r.Position:r.End]) } + raw := rawSb.String() label, next, ok := parseLinkLabel(raw, 0) if !ok {
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-9r42-rhw3-2222ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-14822ghsaADVISORY
- github.com/mattermost/mattermost/commit/4d86263f5430d0eb991fc52ec886cf778cb072e6ghsaWEB
- github.com/mattermost/mattermost/commit/b3d6c0c564c1a79e54e5105d0a8b60fc58a2bdeeghsaWEB
- mattermost.com/security-updatesghsaWEB
- pkg.go.dev/vuln/GO-2026-4325ghsaWEB
News mentions
0No linked articles in our index yet.