URIError: URI malformed - decodeURI in the clerk-js handshake aborts initialization on a malformed URL fragment
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 68/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- javascript, typescript
- Ambito
- authentication, frontend
Direzione di ricerca
Inizia dal percorso di inizializzazione del browser e di handshake del client in clerk-js, quindi riproduci il problema con il frammento URL malformato riportato nel report. Verifica che un frammento non decodificabile non interrompa più l’inizializzazione, mentre i frammenti validi continuino a consentire il completamento dell’handshake e delle richieste client successive.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Preliminary Checks
- I have reviewed the documentation: https://clerk.com/docs
- I have searched for existing issues: https://github.com/clerk/javascript/issues
- I have not already reached out to Clerk support via email or Discord
- This issue is not a question, general help request, or anything other than a bug report directly related to Clerk
Reproduction
https://gist.github.com/RagDam/4a3098709c53c799c8351da0f586e0fe
Publishable key
Not included on purpose: the application is a private family tool. The bug reproduces with
any development instance - the failing call happens in the browser bundle, on a value read
from the current URL, before the instance matters. Happy to provide ours privately if it
helps.
Description
When the current URL carries a fragment that is not a valid percent-encoded sequence, for
example https://<app>/some-page#%E0%A4%A, clerk-js throws while initializing:
URIError: URI malformed
at decodeURI (<anonymous>)
at si (https://<instance>.clerk.accounts.dev/npm/@clerk/clerk-js@6/dist/clerk.browser.js:18:1587)
The call is decodeURI, on a value taken from the current URL, outside any try/catch.
Measured difference. Same page, same signed-in session, only the fragment differs:
| Fragment | Frontend API requests | window.Clerk.session |
window.Clerk.user |
|---|---|---|---|
#anything-valid |
GET /v1/client/handshake (307) x3, POST /v1/environment (200), GET /v1/client (200) |
active | present |
#%E0%A4%A |
GET /v1/client/handshake (307) x3, then nothing |
null | null |
Initialization stops at the handshake: /v1/environment and /v1/client are never
requested, so the client never gets a session.
Why this matters for end users. The session is never refreshed. The short-lived session
token expires (60 s in our development instance, exp - iat), and from then on every route
of the application shows the sign-in screen instead of the requested page. Signing in again
changes nothing, because the same fragment is still in the address bar. The user is locked
out with no way to relate this to the URL.
The input is not exotic: a truncated percent sequence is what a clipped copy-paste produces,
and what some mail clients do when they wrap a long link. Our application links to
/registre#<uuid> from e-mails and from an assistant answer, which is how we ran into it.
Expected. An unreadable fragment is not addressed to Clerk. Reading location.hash never
requires decoding, and decoding a value that comes from the URL should fail softly:
initialization should carry on and treat an undecodable fragment as an absent one.
This is the same class of bug as #9333 (ClerkRequest.parseCookies, malformed percent-escape
in the Cookie header), which was fixed in @clerk/backend. This one is the browser-side
counterpart, on the URL rather than on cookies, and is still present in clerk-js 6 as
loaded by @clerk/nextjs 7.9.1.
Workaround we shipped, an inline script in <head>, before the Clerk bundle runs:
!function () {
function n() {
try { decodeURIComponent(location.hash.slice(1)); }
catch (e) { history.replaceState(null, "", location.pathname + location.search); }
}
n();
addEventListener("hashchange", n);
}();
It removes the unreadable fragment before anything reads it, but every application would have
to know about this.
Environment
@clerk/nextjs: 7.9.1
@clerk/localizations: 4.16.0
clerk-js: 6 (loaded from the CDN as clerk.browser.js)
next: 16.3.4 (App Router, Turbopack)
node: 24.16.0
browser: Chromium 151.0.7922.34 (Playwright)
instance: development
- Lingua principale
- TypeScript
- Stelle
- 1.8k
- Fork
- 472
- Merge medio
- 2g 8h
- PR unite (30g)
- 184
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di clerk/javascript
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
clerk/javascript#9611 · 1 commento ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 86/100
clerk/javascript#9573 ·
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 64/100
clerk/javascript#9775 · 1 commento ·
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
clerk/javascript#9770 · 3 commenti ·
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 52/100
clerk/javascript#9659 · 1 commento ·
Tutte le issue di clerk/javascript
Issue simili
-
Type/Bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
OpenNSW/nsw-srilanka#497 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
0xMiden/bridge-portal#132 ·
-
react-doctor severity:warning tech-debt
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 88/100
digidem/comapeo-cloud-app#403 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100