fix(auth0-express): harden createRouteUrl against path injection attacks#23
Open
cschetan77 wants to merge 2 commits into
Open
fix(auth0-express): harden createRouteUrl against path injection attacks#23cschetan77 wants to merge 2 commits into
cschetan77 wants to merge 2 commits into
Conversation
Strip leading backslashes in addition to forward slashes to prevent WHATWG URL parser normalisation bypasses, and add an explicit scheme check before URL construction to reject javascript:, data:, file: and other scheme-based injection attempts as defence-in-depth. toSafeRedirect is updated to branch on whether input carries a scheme: absolute URLs are validated via origin check directly, while relative paths continue through the strict createRouteUrl validation.
…ardening - Fix scheme regex from /^[a-zA-Z0-9.+-]*:/ to /^[a-zA-Z][a-zA-Z0-9.+-]*:/ so paths with a digit-start first segment (e.g. /2024-report:summary) or a bare leading colon (:param) are not misidentified as URL schemes - Extract SCHEME_REGEX to a named constant shared by createRouteUrl and toSafeRedirect to prevent validation drift - Fix ensureNoLeadingSlash: change * to + and remove the dead g flag - Move new URL(safeBaseUrl).origin inside the try block in toSafeRedirect so a malformed safeBaseUrl returns undefined instead of throwing uncaught - Replace createRouteUrl(req.url, appBaseUrl) in callback-handler with new URL(req.url, appBaseUrl) + origin check, so absolute-form request targets forwarded by reverse proxies are handled correctly - Add tests for single leading backslash, digit-start colon path, colon in non-first segment, toSafeRedirect backslash cases, and malformed safeBaseUrl
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
createRouteUrlis a utility that combines a relative route path with the application base URL. When the path argument can be influenced by an attacker, insufficient validation allows the base URL origin to be overwritten — enabling open redirect and URL injection attacks.What was fixed in a prior commit (7c69b9b)
Commit
7c69b9bintroduced two protections:ensureNoLeadingSlashfrom removing a single/to removing all of them, preventing protocol-relative URL attacks like///evil.com.new URL(path, base), the result's origin is compared to the base URL's origin and an error is thrown if they differ.What remained unmitigated
Two gaps were left unaddressed:
1. Backslashes not stripped
ensureNoLeadingSlashonly handled forward slashes. The WHATWG URL parser normalises backslashes to forward slashes, so inputs like\\evil.comor\/evil.comwere treated as protocol-relative URLs (//evil.com) by the parser — overriding the base host.2. No scheme check before URL construction
There was no pre-construction check for URL schemes. Inputs like
javascript:alert(1),data:text/html,..., orfile:///etc/passwdhave no leading slashes so the multi-slash check was skipped entirely. While the origin check caught these (theiroriginisnullor a different host), relying on a single post-construction safety net is insufficient defence-in-depth.What this PR fixes
ensureNoLeadingSlashStrips both leading forward slashes and backslashes using
/^[/\\]+/, closing the backslash normalisation bypass. The*quantifier is also corrected to+(only strip when leading characters are actually present).SCHEME_REGEX— shared named constantThe scheme detection regex is extracted to a single named constant used by both
createRouteUrlandtoSafeRedirect, preventing future validation drift. The regex is tightened to/^[a-zA-Z][a-zA-Z0-9.+-]*/per RFC 3986 — a scheme must start with a letter, so paths like/2024-report:summaryor:paramare correctly treated as relative paths rather than being misidentified as schemes.createRouteUrlAdds an explicit scheme check using
SCHEME_REGEXon the normalised path before passing it tonew URL(). If a scheme is detected the function throws immediately — failing fast rather than relying solely on the post-construction origin check.toSafeRedirecttoSafeRedirectaccepts user-supplied input which can legitimately be an absolute same-origin URL (e.g.returnTo=https://myapp.com/profile). SincecreateRouteUrlnow rejects any scheme,toSafeRedirectis updated to branch on whether the input carries a scheme:new URL()and validated by origin check.createRouteUrlvalidation.new URL(safeBaseUrl).originis also moved inside thetryblock so a malformedsafeBaseUrlreturnsundefinedinstead of throwing uncaught.callback-handler.tsreq.urlis normally an origin-form path (/auth/callback?...) but can arrive as a full absolute URL when a request is forwarded by a reverse proxy.createRouteUrlis designed for SDK config paths (always relative) and its scheme check would throw on absolute-form request targets, causing a 500.The handler now uses
new URL(req.url, appBaseUrl)directly with an explicit origin check, which correctly handles both forms. Any parse error is caught by the existing outercatchand returned as a 500.Attack vectors guarded against
///evil.com,///evil.com\\evil.com,\/evil.com,/\evil.comhttps://evil.com/pathjavascript:injectionjavascript:alert(1)data:injectiondata:text/html,<script>...</script>file:injectionfile:///etc/passwd\thttps://evil.comhttps://evil.comTesting
Unit Tests (
packages/auth0-express/src/utils.spec.ts):throws when path has multiple leading slashes— error message updated to include backslashesthrows when path has multiple leading backslashes—\\evil.comthrows when path has mixed leading slash and backslash—/\evil.com,\/evil.comthrows when path is an absolute URL with a scheme— now expects scheme-specific error messagethrows when path uses http scheme to override the base URL origin— now expects scheme-specific error messagethrows when path uses javascript scheme—javascript:alert(1)throws when path uses data scheme—data:text/html,...throws when path uses file scheme—file:///etc/passwdsingle leading backslash is stripped and resolves as a same-origin relative path— documents safe asymmetryallows paths with a colon in non-first segment—/a/b:callows paths whose first segment starts with a digit followed by a colon—/2024-report:summarytoSafeRedirect— double backslash and mixed slash/backslash casestoSafeRedirect— returns undefined whensafeBaseUrlis not a valid URL