Skip to content

DOM-Based XSS in Homarr /auth/login Redirect

High
Meierschlumpf published GHSA-79pg-554g-rw82 Apr 3, 2026

Package

ghcr.io/homarr-labs/homarr (Docker image)

Affected versions

<= 1.56.1

Patched versions

>= 1.57.0

Description

Project: Homarr (https://github.com/homarr-labs/homarr)
Vulnerability Type: DOM-Based Cross-Site Scripting (XSS)
Severity: High (CVSS 3.1 Base Score: 8.8)
Report Date: March 21, 2026

1. Summary

A DOM-based Cross-Site Scripting (XSS) vulnerability has been discovered in Homarr's /auth/login page. The application improperly trusts a URL parameter (callbackUrl), which is passed to redirect 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 credential theft, internal network pivoting, and unauthorized actions performed on behalf of the victim.

2. Vulnerability Details

2.1. Affected Component and Code

There are two code sinks which lead to XSS. The first is triggered if the user is already authenticated. The second is triggered if the user is not authenticated, but proceeds to submit a sign-in form.

// auth/login/page.tsx
const searchParams = await props.searchParams;
const session = await auth();

if (session) {
  redirect(searchParams.callbackUrl ?? "/"); // <-- sink
}

// [...]

return (
  // [...]
    <LoginForm
      providers={env.AUTH_PROVIDERS}
      oidcClientName={env.AUTH_OIDC_CLIENT_NAME}
      isOidcAutoLoginEnabled={env.AUTH_OIDC_AUTO_LOGIN}
      callbackUrl={searchParams.callbackUrl ?? "/"} // <-- sink
    />
// auth/login/_login-form.tsx
export const LoginForm = ({ /* ... */ callbackUrl }: LoginFormProps) => {
  const onSuccess = useCallback(
    async (provider: Provider, response: Awaited<ReturnType<typeof signIn>>) => {
      // [...]
      router.push(callbackUrl); // <-- sink
    },
    [t, router, callbackUrl],
  );

As shown, the callbackUrl parameter is taken from the browser's URL query and later passed to redirect or router.push without validating against the javascript: protocol, leading to XSS. redirect is called if a session exists (i.e. user is already authenticated), and router.push is called after an unauthenticated user successfully logs in.

This happens because redirect and router.push 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:

    http://HOST:7575/auth/login?callbackUrl=javascript:alert(window.origin)
    

    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: A victim clicks the link.

    1. If the victim is already authenticated, no further action is required and the XSS is triggered.
    2. If the victim is not authenticated, the XSS only triggers upon a successful login.

2.3. Screenshot

homarr_xss

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:

  • 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 callbackUrl 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 (callbackUrl && callbackUrl.startsWith("/") && !callbackUrl.startsWith("//")) {
  redirectPath = callbackUrl;
} 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 callbackUrl passes validation, it can be safely used; otherwise, fall back to a default safe path like /.

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

6. Timeline and Disclosure Process

  • 2026-03-21: Vulnerability discovered and this report prepared.
  • 2026-03-21: Report sent to Homarr security contact / maintainers.
  • 2026-03-21: Maintainer acknowledges receipt of the report and implements a fix.
  • 2026-04-04: Maintainer publishes security advisory on GHSA.

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
Required
Scope
Changed
Confidentiality
High
Integrity
Low
Availability
Low

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:L

CVE ID

CVE-2026-33510

Weaknesses

Improper Neutralization of Alternate XSS Syntax

The product does not neutralize or incorrectly neutralizes user-controlled input for alternate script syntax. Learn more on MITRE.

URL Redirection to Untrusted Site ('Open Redirect')

The web application accepts a user-controlled input that specifies a link to an external site, and uses that link in a redirect. Learn more on MITRE.

Credits