Skip to content

Instantly share code, notes, and snippets.

@TrebledJ
Last active April 15, 2026 06:13
Show Gist options
  • Select an option

  • Save TrebledJ/fe7241910ac0aaeff86243fc88e9ffed to your computer and use it in GitHub Desktop.

Select an option

Save TrebledJ/fe7241910ac0aaeff86243fc88e9ffed to your computer and use it in GitHub Desktop.

Coordinated Disclosure Report: DOM-Based XSS and Open Redirect in Kortix-AI Suna

Project: Kortix-AI Suna (https://github.com/kortix-ai/suna)
Vulnerability Type: DOM-Based Cross-Site Scripting (XSS), Open Redirect
Severity: High (CVSS 3.1 Base Score: 8.8)
Report Date: April 10, 2026

1. Summary

A DOM-based Cross-Site Scripting (XSS) vulnerability has been discovered in Kortix AI Suna's /auth and /auth/password pages. The application improperly trusts a URL parameter (returnUrl), which is passed to router.replace and router.push. An attacker can craft a malicious link that, when opened by an authenticated user, performs a client-side redirect and executes arbitrary JavaScript in the context of their browser. This could lead to session hijacking, credential theft, internal network pivoting, and unauthorized actions performed on behalf of the victim.

2. Vulnerability Details

2.1. Affected Component and Code

Specific Lines:

// app/auth/page.tsx
function LoginContent() {
  const router = useRouter();
  const searchParams = useSearchParams();
  // [...]
  const rawReturnUrl = searchParams.get('returnUrl') || searchParams.get('redirect');
  const returnUrl = rawReturnUrl?.match(/^\/instances\/[^/]+/) ? '/instances' : rawReturnUrl;
  // [...]
  useEffect(() => {
    if (!isLoading && user) {
      router.replace(returnUrl || '/instances'); // <-- sink (Line 199)
    }
  }, [user, isLoading, router, returnUrl]);

(The other sinks and affected components are similar, and the other code snippets have been excluded for conciseness.)

As shown, the returnUrl parameter is taken from the browser's URL query and later passed to router.push or router.replace without validating against the javascript: protocol, leading to XSS. This happens because router.push and router.replace pass its parameter to window.location, which is known to parse and execute JavaScript in javascript: URIs. (Note: According to previous discussions, the stance from the NextJS maintainers is that library users are responsible for applying sanitisation for input passed to router.push and router.replace. See this NextJS GitHub issue.)

2.2. Steps to Reproduce and Proof of Concept (PoC)

  1. Attacker crafts a malicious URL:

    https://HOST/auth/password?returnUrl=javascript:alert(window.origin)
    https://HOST/auth/password?returnUrl=javascript:alert(atob(document.cookie.split(%22;%22).find(r=%3Er.includes(%22kortix-auth%22))?.split(%22=%22)[1].substring(7)))
    

    A sophisticated payload could hide the JavaScript by inserting extra query parameters or using URL encoding to obfuscate the attack, making the URL appear less suspicious to victims.

  2. Victim Action: An authenticated victim clicks the link and the XSS is triggered.

2.3. Screenshot

PoC: image

Impact - can exfiltrate access token: image

PoC (app/auth/password/page.tsx): image

3. CVSS v3.1 Score Justification

Base Score: 8.8 (High)
Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:L

  • Attack Vector (AV): Network (N) – The vulnerability is exploitable remotely over the network via a crafted URL.
  • Attack Complexity (AC): Low (L) – The attack does not require complex conditions.
  • Privileges Required (PR): None (N) – No authentication or privileges are required by the attacker to trigger the vulnerability.
  • User Interaction (UI): Required (R) – The victim must click on the attacker's malicious link and, if unauthenticated, perform a signup action.
  • Scope (S): Changed (C) – The vulnerable component is the client-side code, but the impact (executing arbitrary script) affects the user's browser session and the data accessible within the application's security context.
  • Confidentiality (C): High (H) – Successful exploitation could lead to complete loss of confidentiality. An attacker can call authenticated API endpoints and other information stored in the browser's context.
  • Integrity (I): Low (L) – An attacker could modify data or perform actions on behalf of the user.
  • Availability (A): Low (L) – In a reasonable worst case scenario, an administrator is compromised, leading to potential actions which affect the availability of the system.

4. Impact

Successful exploitation of this vulnerability has a High impact:

  • Session Hijacking: An attacker could steal the victim's session token or authentication cookies, gaining complete access the account, files, and data.
  • Arbitrary Actions: The script could use the victim's active session to make API requests, create, modify, or delete items, or perform any action the victim is authorized to do.
  • Credential Theft: A script could present a fake login prompt within the context of the legitimate site to capture the user's credentials.
  • Internal Network Pivoting: If the victim is within an internal network, the XSS could be used as a foothold to perform attacks against other internal systems from the victim's browser.

5. Remediation Recommendations

To fix this vulnerability, the application should validate and sanitise the returnUrl variable before using it for redirection. Here are a few approaches:

5.1. Approach 1

This approach only allows absolute URL paths such as /abc and protects against open redirects such as //example.com/path.

if (returnUrl && returnUrl.startsWith("/") && !returnUrl.startsWith("//")) {
  redirectPath = returnUrl;
} else {
  redirectPath = '/'; // Safe default
}

5.2. Approach 2

This approach allows for http:// and https:// scheme in the redirect URL, but also protects against open redirect. Functionally, it is the same as Approach 1.

  1. Validate the redirect path stays within the same origin and uses a safe scheme. Use the URL constructor to parse the path relative to the current origin and check both the origin and the protocol:

    function isValidRedirectPath(path) {
      try {
        // Parse relative paths correctly by providing the current origin as the base
        const url = new URL(path, window.location.origin);
        // Ensure the origin matches AND the scheme is either http: or https:
        return url.origin === window.location.origin && 
              (url.protocol === 'http:' || url.protocol === 'https:');
      } catch {
        return false;
      }
    }

    This validation correctly handles:

    • Relative paths like /dashboard (resolves to https://example.com/dashboard)
    • Absolute paths within the same origin like https://example.com/pipelines
    • Blocks cross-origin and open redirects like //attacker.site/index.html and https://attacker.site/
    • Blocks dangerous schemes like javascript:, data:, vbscript:, etc.
  2. Apply validation before any navigation. If returnUrl passes validation, it can be safely used; otherwise, fall back to a default safe path like /.

    if (returnUrl && isValidRedirectPath(returnUrl)) {
      redirectPath = returnUrl;
    } else {
      redirectPath = '/'; // Safe default
    }

Sensitive Cookies Should Be HttpOnly

Further, to mitigate the blast radius of future XSS risks, it is recommended that sensitive cookies related to session identification be marked as HttpOnly. This may require further adjuments to the client-side code. Currently, sb-kortix-auth-token has HttpOnly=False.

image

6. Timeline and Disclosure Process

  • 2026-04-10: Vulnerability discovered.
  • 2026-04-10: Report sent to Suna security contact / maintainers.
  • [Pending]: Maintainer acknowledges receipt of the report.
  • [Pending]: Maintainer discloses security advisory, e.g. by publishing via GitHub's security advisory program.

7. Disclosure Policy

A 45-day disclosure deadline is set for May 25, 2026, in accordance with standard coordinated disclosure practice. Details will be published on that date; or sooner if a fix is released or if the maintainer declines to address the issue. This approach is intended to inform users of potential risks in a timely manner. I understand that vendors may operate on their own timelines, and I am open to discussing adjustments to this deadline where warranted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment