Skip to content

fix(web3): sanitize chain RPC URL before injecting into in-app browser (UXSS)#3440

Open
jim-daf wants to merge 1 commit into
AlphaWallet:masterfrom
jim-daf:fix/security-issue-2686
Open

fix(web3): sanitize chain RPC URL before injecting into in-app browser (UXSS)#3440
jim-daf wants to merge 1 commit into
AlphaWallet:masterfrom
jim-daf:fix/security-issue-2686

Conversation

@jim-daf
Copy link
Copy Markdown

@jim-daf jim-daf commented Apr 19, 2026

Sanitize the chain RPC URL before injecting it into in-app browser pages

Resolves #2686 - Universal XSS via wallet_addEthereumChain RPC URL.

The vulnerability

JsInjectorClient.loadInitJs(...) builds the JavaScript that is injected into
every page loaded in the AlphaWallet dApp browser by interpolating the active
chain's RPC URL into a template with String.format:

return String.format(initSrc, address, rpcUrl, chainId);

The RPC URL is whatever value the network record holds, which a malicious dApp
can control by calling wallet_addEthereumChain with a payload like:

rpcUrls: ['https://rpc-mumbai.matic.today/x"+alert(document.domain)+"']

After the user accepts the new chain (a benign-looking confirmation), every
subsequent page loaded in the in-app browser is poisoned with the attacker's
JavaScript, executed in the origin of that page — a classic stored UXSS.

What this PR does

app/src/main/java/com/alphawallet/app/web3/JsInjectorClient.java:

  1. Adds sanitizeRpcUrl(String) which:
    • rejects empty input;
    • rejects URLs containing characters that have meaning inside a JavaScript
      string literal (", ', \, <, >, CR, LF, tab, other control
      bytes);
    • parses with OkHttp's HttpUrl.parse(...) and rejects anything that
      isn't a valid http/https URL;
    • returns the canonical, normalized URL and re-checks it for unsafe
      characters in case the parser decoded any.
  2. Pipes the value resolved by
    EthereumNetworkRepository.getDefaultNodeURL(chainId) through that helper
    inside both setChainId and setTSChainId so the field stored on the
    client is always safe to splice.
  3. Coalesces a null rpcUrl to "" in loadInitJs so String.format never
    sees null after the change.

…s (UXSS)

Resolves AlphaWallet#2686

JsInjectorClient.loadInitJs splices the configured RPC URL into a JavaScript
template via String.format and the result is injected into every page that
loads in the in-app dApp browser. A malicious dApp could exploit this by
calling wallet_addEthereumChain with an RPC URL such as

    https://rpc.example/x"+alert(document.domain)+"

After the user accepts the new chain, the URL is persisted to the network
database and used as-is on every subsequent page load, breaking out of the
RPC-URL string literal in the template and giving the attacker a stored,
universal XSS that runs in the origin of any site visited in the browser
(including unrelated dApps and major sites).

This change adds a sanitizeRpcUrl helper that:

  * Rejects empty/null URLs.
  * Rejects URLs containing any character with meaning inside a JS string
    literal (quotes, backslash, angle brackets, control characters).
  * Parses the URL with HttpUrl.parse and rejects anything that is not a
    valid http(s) URL.
  * Returns the canonical normalized URL string and re-checks it for
    unsafe characters before returning.

setChainId and setTSChainId now run the resolved RPC URL through this
helper before storing it. If the URL is unsafe, an empty string is used,
which makes the injected provider non-functional for that chain but
prevents the UXSS payload from executing.

Defensive: loadInitJs also coalesces a null rpcUrl to an empty string so
String.format never sees null after the change.
@jim-daf jim-daf changed the title fix: validate and sanitize URLs in Web3TokenView.java fix(web3): sanitize chain RPC URL before injecting into in-app browser (UXSS) Apr 21, 2026
@jim-daf jim-daf force-pushed the fix/security-issue-2686 branch from cda0e83 to 28771ec Compare April 21, 2026 19:52
@jim-daf jim-daf marked this pull request as ready for review April 21, 2026 20:42
@jim-daf jim-daf requested a review from JamesSmartCell as a code owner April 21, 2026 20:42
Copilot AI review requested due to automatic review settings April 21, 2026 20:42
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR mitigates a stored universal-XSS (UXSS) vector in AlphaWallet’s in-app dApp browser by sanitizing the active chain’s RPC URL before it is interpolated into injected JavaScript.

Changes:

  • Introduces sanitizeRpcUrl(String) to validate/normalize RPC URLs and reject inputs unsafe for JS string literal splicing.
  • Applies RPC URL sanitization when setting chainId for both normal and TokenScript injection paths.
  • Ensures loadInitJs never passes a null RPC URL into String.format.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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.

UXSS

2 participants