diff --git a/public/miniapp/redirect.html b/public/miniapp/redirect.html index 81de650..b6e5151 100644 --- a/public/miniapp/redirect.html +++ b/public/miniapp/redirect.html @@ -124,7 +124,21 @@ document.getElementById('errorText').textContent = t.error; document.getElementById('manualBtn').textContent = t.btn; - if (!url) { + // SECURITY: this page navigates to a user-supplied `url`. Only open + // a custom app deep link. A bare `javascript:`/`data:`/`vbscript:`/ + // `file:` URI (DOM-XSS) is not scheme://-shaped, and http(s)/intent + // are blocked (open redirect / intent abuse) — so only VPN app + // schemes (happ://, vless://, ...) pass. Mirrors the validation in + // src/pages/DeepLinkRedirect.tsx. + function isSafeAppLink(raw) { + var s = String(raw || '').trim().toLowerCase(); + var m = s.match(/^([a-z][a-z0-9+.\-]*):\/\//); + if (!m) return false; + var blocked = ['http', 'https', 'file', 'blob', 'about', 'javascript', 'data', 'vbscript', 'intent', 'content']; + return blocked.indexOf(m[1]) === -1; + } + + if (!url || !isSafeAppLink(url)) { document.getElementById('title').textContent = t.noUrl; document.getElementById('subtitle').textContent = ''; document.querySelector('.spinner').style.display = 'none';