GHSA-F3G8-9XV5-77GV

Vulnerability from github – Published: 2026-04-16 23:00 – Updated: 2026-05-11 13:29
VLAI
Summary
Saltcorn: Open Redirect in `POST /auth/login` due to incomplete `is_relative_url` validation (backslash bypass)
Details

Summary

Saltcorn validates the post-login dest parameter with a string check that only blocks :/ and //. Because all WHATWG-compliant browsers normalise backslashes (\) to forward slashes (/) for special schemes, a payload such as /\evil.com/path slips through is_relative_url(), is emitted unchanged in the HTTP Location header, and causes the browser to navigate cross-origin to an attacker-controlled domain. The bug is reachable on a default install and only requires a victim who can be tricked into logging in via a crafted Saltcorn URL.

Details

Vulnerable function: packages/server/routes/utils.js:393-395

const is_relative_url = (url) => {
  return typeof url === "string" && !url.includes(":/") && !url.includes("//");
};

The function's intent is to allow only same-origin redirects, but the allow-list only checks for two literal substrings. It does not handle: - backslash characters, which WHATWG URL parsing (used by every modern browser) treats as forward slashes for the special schemes http, https, ftp, ws, wss. A URL parser fed /\evil.com/path with a base of http://victim/ resolves to http://evil.com/path. - non-http(s): schemes that do not contain :/. The strings javascript:alert(1), data:text/html,..., vbscript:... all pass.

Vulnerable callsite: packages/server/auth/routes.js:1371-1376

} else if (
  (req.body || {}).dest &&
  is_relative_url(decodeURIComponent((req.body || {}).dest))
) {
  res.redirect(decodeURIComponent((req.body || {}).dest));
} else res.redirect("/");

The body's dest is URL-decoded twice (once by body-parser, once by the explicit decodeURIComponent) and the same value is passed to res.redirect. Express 5's res.redirect runs the value through encodeurl@2.0.0, whose whitelist character class [^\x21\x23-\x3B\x3D\x3F-\x5F\x61-\x7A\x7C\x7E] includes \x5C (backslash). The backslash is therefore not percent-encoded and ends up verbatim in the Location response header.

PoC

poc.zip

Please extract the uploaded compressed file before proceeding 1. ./setup.sh 2. ./poc.sh

스크린샷 2026-04-13 오후 11 44 36

Impact

Any user who can be lured into clicking a Saltcorn login URL crafted by the attacker will, after submitting their valid credentials, be redirected to an attacker-controlled origin. The redirect happens under the trusted Saltcorn domain, so the user has no visual cue that they are about to leave the site. Realistic abuse patterns:

  • Credential phishing — the attacker's site renders a forged "session expired, please log in again" prompt to capture the password the user just typed.
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "@saltcorn/server"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.4.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "@saltcorn/server"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.5.0-beta.0"
            },
            {
              "fixed": "1.5.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "@saltcorn/server"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.6.0-alpha.0"
            },
            {
              "fixed": "1.6.0-beta.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-42259"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-601"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-16T23:00:45Z",
    "nvd_published_at": "2026-05-07T20:16:44Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\nSaltcorn validates the post-login `dest` parameter with a string check that only blocks `:/` and `//`. Because all WHATWG-compliant browsers normalise backslashes (`\\`) to forward slashes (`/`) for special schemes, a payload such as `/\\evil.com/path` slips through `is_relative_url()`, is emitted unchanged in the HTTP `Location` header, and causes the browser to navigate cross-origin to an attacker-controlled domain. The bug is reachable on a default install and only requires a victim who can be tricked into logging in via a crafted Saltcorn URL.\n\n### Details\nVulnerable function: `packages/server/routes/utils.js:393-395`\n\n```js\nconst is_relative_url = (url) =\u003e {\n  return typeof url === \"string\" \u0026\u0026 !url.includes(\":/\") \u0026\u0026 !url.includes(\"//\");\n};\n```\n\nThe function\u0027s intent is to allow only same-origin redirects, but the allow-list only checks for two literal substrings. It does not handle:\n- backslash characters, which WHATWG URL parsing (used by every modern browser) treats as forward slashes for the special schemes `http`, `https`, `ftp`, `ws`, `wss`. A URL parser fed `/\\evil.com/path` with a base of `http://victim/` resolves to `http://evil.com/path`.\n- non-`http(s):` schemes that do not contain `:/`. The strings `javascript:alert(1)`, `data:text/html,...`, `vbscript:...` all pass.\n\nVulnerable callsite: `packages/server/auth/routes.js:1371-1376`\n\n```js\n} else if (\n  (req.body || {}).dest \u0026\u0026\n  is_relative_url(decodeURIComponent((req.body || {}).dest))\n) {\n  res.redirect(decodeURIComponent((req.body || {}).dest));\n} else res.redirect(\"/\");\n```\n\nThe body\u0027s `dest` is URL-decoded twice (once by body-parser, once by the explicit `decodeURIComponent`) and the same value is passed to `res.redirect`. Express 5\u0027s `res.redirect` runs the value through `encodeurl@2.0.0`, whose whitelist character class `[^\\x21\\x23-\\x3B\\x3D\\x3F-\\x5F\\x61-\\x7A\\x7C\\x7E]` includes `\\x5C` (backslash). The backslash is therefore not percent-encoded and ends up verbatim in the `Location` response header.\n\n### PoC\n[poc.zip](https://github.com/user-attachments/files/26678853/poc.zip)\n\nPlease extract the uploaded compressed file before proceeding\n1. ./setup.sh\n2. ./poc.sh\n\n\u003cimg width=\"419\" height=\"71\" alt=\"\u1109\u1173\u110f\u1173\u1105\u1175\u11ab\u1109\u1163\u11ba 2026-04-13 \u110b\u1169\u1112\u116e 11 44 36\" src=\"https://github.com/user-attachments/assets/9c919ed4-167b-47e3-9873-733f97b44bf0\" /\u003e\n\n### Impact\nAny user who can be lured into clicking a Saltcorn login URL crafted by the attacker will, after submitting their valid credentials, be redirected to an attacker-controlled origin. The redirect happens under the trusted Saltcorn domain, so the user has no visual cue that they are about to leave the site. Realistic abuse patterns:\n\n- Credential phishing \u2014 the attacker\u0027s site renders a forged \"session expired, please log in again\" prompt to capture the password the user just typed.",
  "id": "GHSA-f3g8-9xv5-77gv",
  "modified": "2026-05-11T13:29:07Z",
  "published": "2026-04-16T23:00:45Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/saltcorn/saltcorn/security/advisories/GHSA-f3g8-9xv5-77gv"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42259"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/saltcorn/saltcorn"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Saltcorn: Open Redirect in `POST /auth/login` due to incomplete `is_relative_url` validation (backslash bypass)"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…