POSTED BY: Ioannis Christodoulakos / 16.03.2023

Reflected XSS vulnerabilities in Squidex "/squid.svg" endpoint

CENSUS ID:CENSUS-2023-0001
CVE ID:CVE-2023-24278
Affected Products:Squidex versions prior to 7.4.0
Class:Improper Neutralization of Input During Web Page Generation (CWE-79)
Discovered by:Ioannis Christodoulakos

CENSUS has discovered two reflected cross site scripting (XSS) vulnerabilities in the Squidex open source headless CMS software. The Reflected Cross Site Scripting vulnerabilities affect all versions of Squidex prior to 7.4.0 and affect both authenticated and unauthenticated victim users. The Squidex development team has addressed the issues in version 7.4.0 of the software.

Vulnerability Details

CENSUS identified two Reflected XSS (Cross-site scripting) vulnerabilities affecting the Squidex "headless" CMS framework, during an application security assessment of a web application based on Squidex. These vulnerabilities enable attackers to embed malicious JavaScript code into a link and have the malicious code be executed within a victim user's browser when the victim user clicks the malicious link. The flaws affect the "/squid.svg" endpoint, which is accessible to both authenticated and unauthenticated users. Attackers may employ these vulnerabilities to extract the CMS token from the browser's local storage, allowing them to take control of the user's CMS session. The vulnerabilities affect versions prior to Squidex 7.4.0. CENSUS has confirmed this to be the case for versions 5.0.0 and 6.8.0.

The issue stems from the fact that the application fails to embed user-supplied data as text in an auto-generated SVG image, allowing for the introduction of arbitrary SVG elements, including elements that may include malicious JavaScript code. The user-supplied data are passed to the "/squid.svg" endpoint through a GET request requiring no authentication. Malicious code passed as a parameter to this endpoint, is "reflected" back to the visitor's browser, thus allowing an attacker to execute arbitrary JavaScript code on victim browsers through the distribution of a malicious URL.

The vulnerable code in question is shown below:

// File: backend/src/Squidex/Pipeline/Squid/SquidMiddleware.cs
...
 public sealed class SquidMiddleware
{
...
    private static (string, string, string) SplitText(string text)
    {
        var result = new List();

        var line = new StringBuilder();

        foreach (var word in text.Split(' '))
        {
            if (line.Length + word.Length > 16 && line.Length > 0)
            {
                result.Add(line.ToString());

                line.Clear();
            }

            line.AppendIfNotEmpty(' ');
            line.Append(word);
        }

        result.Add(line.ToString());

        while (result.Count < 3)
        {
            result.Add(string.Empty);
        }

        return (result[0], result[1], result[2]);
    }

    public async Task InvokeAsync(HttpContext context)
     {
            var request = context.Request;
...
            if (request.Query.TryGetValue("title", out var titleValue) && !string.IsNullOrWhiteSpace(titleValue))
            {
                title = titleValue;
            }
            var text = "text";

             if (request.Query.TryGetValue("text", out var textValue) && !string.IsNullOrWhiteSpace(textValue))
             {
                 text = textValue;
             }

             var background = isSad ? "#F5F5F9" : "#4CC159";

            if (request.Query.TryGetValue("background", out var backgroundValue) && !string.IsNullOrWhiteSpace(backgroundValue))
             {
                background = backgroundValue;
             }
...
             var (l1, l2, l3) = SplitText(text);

             svg = svg.Replace("{{TITLE}}", title.ToUpperInvariant(), StringComparison.Ordinal);
             svg = svg.Replace("{{TEXT1}}", l1, StringComparison.Ordinal);
             svg = svg.Replace("{{TEXT2}}", l2, StringComparison.Ordinal);
             svg = svg.Replace("{{TEXT3}}", l3, StringComparison.Ordinal);
             svg = svg.Replace("[COLOR]", background, StringComparison.Ordinal);

             context.Response.StatusCode = 200;
             context.Response.ContentType = "image/svg+xml";
             context.Response.Headers["Cache-Control"] = "public, max-age=604800";

             await context.Response.WriteAsync(svg, context.RequestAborted);
         }
...

In the above code snippet in method InvokeAsync() the text user-supplied parameter is being split into three lines, via SplitText(), and is then embedded "as is" into the generated SVG image, thus allowing for SVG markup injection. Moreover, the background user-supplied parameter is simply copied "as is" to the generated SVG image, again allowing for SVG markup injection. Finally, the "title" is also a user-supplied parameter, however due to it being transformed to uppercase one would not be able to inject malicious JavaScript code (due to the case-sensitive nature of SVG tags). Therefore, it is possible for an attacker to conduct a reflected XSS attack by abusing either the text or background parameters (or both).

The example below demonstrates a reflected XSS attack via the background parameter:


GET /squid.svg?title=Not%20Found&text=This%20is%20not%20the%20page%20you%20are%20looking%20for!&background=%22%3E%3Cscript%3Ealert(1)%3C/script%3E%3Cimg%20src=%22&small HTTP/2
[...]

HTTP/2 200 OK
Content-Type: image/svg+xml
[...]

<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 391.9">
  [...]
  <path d="M349 [...] 67.5-3.8z" fill=""><script>alert(1)</script><img src=""/>
  <text transform="translate(97.559 104.938)" letter-spacing="1" class="st6 st71" fill="#4cc159">
    NOT FOUND
  </text>
  <text transform="translate(97.559 147.894)">
    <tspan x="0" y="00" class="st5 st6 st70">This is not the</tspan>
    <tspan x="0" y="28" class="st5 st6 st70">page you are</tspan>
    <tspan x="0" y="56" class="st5 st6 st70">looking for!</tspan>
  </text>
  [...]
</svg>

CVE-2023-24278 has been assigned to these vulnerabilities.

Recommendation

It is highly recommended to upgrade to version 7.4.0 of Squidex or newer to mitigate the aforementioned vulnerabilities.

Disclosure Timeline

Vendor Contact:July 7, 2022
Vendor Confirmation:Janurary 12, 2023
Vendor Fix Released:February 1, 2023
CVE Allocation:February 25, 2023
Public Advisory:March 16, 2023