Repository navigation
feat(wallet): sign tx via browser wallet localhost handoff - #1079
Merged
Nanle-code merged 2 commits intoOct 1, 2026
Merged
Conversation
…localhost handoff
Owner
|
@Henrypave fix conflicts |
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.
Overview
Adds a browser-wallet signing path so StarForge users can keep keys in
Freighter (or any Stellar Wallets Kit compatible wallet) instead of importing a
secret into the CLI.
starforge wallet sign-tx --signer browserstarts aone-time HTTP server bound to
127.0.0.1, opens a page that displays a decodedview of the transaction and asks the wallet to sign it, then returns the signed
envelope XDR to the CLI. The handoff is authorised by a single-use 32-byte
nonce, served under a strict
Content-Security-Policy, and expires after ashort timeout.
Related Issue
Addresses Nanle-code/StarForge#956:
--signer browsershould serve a one-time localhost page with a nonce,display the decoded transaction, return the signed XDR to the CLI, bind
127.0.0.1, use a tight CSP, and keep a short timeout.No new dependencies were added and no lockfile was touched. The handoff uses
std::net::TcpListenerwith a minimal HTTP/1.1 request/response loop, pluscrates the crate already depends on (
serde,serde_json,sha2,hex,base64,rand).Changes
src/utils/browser_signer.rsHandoffServer: binds127.0.0.1:0, serves an ephemeral-port handoff, andstops as soon as a signature arrives or the timeout elapses.
NonceGuard: 32-byte OS-RNG nonce, constant-time comparison, single-use(consumed only after a well-formed signature is validated).
GET /(page, nonce required),GET /api/transaction(JSON withthe unsigned XDR, network passphrase, and
DecodedTransaction),POST /api/sign-result(validates base64 envelope XDR, consumes the nonce,returns the signed XDR to the waiting CLI). Everything else is
404.content_security_policy:default-src 'none'with a script nonce plus apinned Stellar Wallets Kit CDN origin,
connect-src 'self',frame-ancestors 'none',base-uri 'none',form-action 'none'.WalletSignertrait withLocalhostHandoffSigner(real, opens the browser)and
MockWalletSigner(tests/dry runs) so the flow is testable without abrowser.
DecodedTransaction: base64 validity, byte length, envelope-type labelfrom the XDR discriminant, SHA-256 digest, and a hex preview.
strict CSP, page nonce gating, malformed signature not burning the nonce,
replaying a used nonce returning
410, a realTcpStreamhandshakeround-trip, timeout, and mock-signer success/failure paths.
src/utils/mod.rspub mod browser_signer;.src/commands/wallet.rswallet sign-txsubcommand with--transaction,--signer browser|local,--wallet,--network,--output, and--timeout.--signer browseruses the handoff and never reads a secret key;--signer localreuses the existingutils::wallet_signerlocal path.docs/SECURITY_THREAT_MODEL.md(loopback-only + single-use nonce; validate before accepting), and a
"Browser-wallet localhost handoff" threat/mitigation section.
docs/BROWSER_WALLET_SIGNING.mdVerification Results
--signer browserserves a one-time localhost page with a noncewallet sign-tx --signer browser→browser_signer::HandoffServerwithNonceGuardDecodedTransactionpage +/api/transactionand/api/sign-result127.0.0.1, short timeoutContent-Security-Policy, loopback ephemeral bind,--timeout(default 120s)docs/BROWSER_WALLET_SIGNING.md(not executed in this environment)MockWalletSignerinsrc/utils/browser_signer.rs(not executed in this environment)docs/SECURITY_THREAT_MODEL.mdboundary row + handoff sectionNote on the browser page: the page imports a pinned Stellar Wallets Kit bundle
from
https://cdn.jsdelivr.netbecause the crate cannot vendor the JS withoutadding build tooling. The exact CDN module entry point and kit API version were
not exercised in a browser here; the manual checklist is how that is confirmed.
Closes #956