Component: ghost-extension-wallet @ 66bd207, src/inpage/pjsInject.ts:22-24, src/background/createBackgroundRpc.ts:271-278.
Description: The enable function in pjsInject.ts ignores origin entirely, with an explicit comment in the code:
injectExtension(
async (_origin) => {
// TODO: validate allowed origin
The getAccounts background handler (createBackgroundRpc.ts:47-62) asks for no user consent at all. The middleware only restricts the web channel to 3 methods (createTx, getAccounts, pjsSignPayload), and all three are callable from ANY origin. Origin is only logged (port.sender?.url, set by the browser, not forgeable by the page) for display in the popup. There is no origin allowlist and no “connect” prompt like the polkadot-js extension pattern.
Impact: (a) Privacy leak: any malicious site the user visits immediately gets all addresses + chains with no interaction, enabling fingerprinting and targeting. (b) Sign-request spam: a site can open repeated approval popups (each request = a new chrome.windows.create) for social engineering / click-fatigue. Funds are not directly at risk because each sign needs an explicit Approve click in a separate popup showing the origin.
Reproduction:
Static: open any site with the content script injected → window.injectedWeb3["<name>"].enable("https://evil.example") → accounts.get() returns all addresses with no prompt. Code path: pjsInject.ts:28-48 → rpc.getAccounts → keyring.getAccounts. Passive (reads own addresses only).
Severity: Medium. Reason: no direct fund loss (signing still needs per-popup approval), but non-consensual address enumeration is a real privacy violation for a wallet, and sign-spam is a phishing amplifier. Comparable to the commonly Medium-rated “missing connection prompt” class in wallet audits.
Recommendation: Implement an origin allowlist in chrome.storage.local plus a first-time per-origin connection consent prompt (polkadot-js extension pattern); gate getAccounts behind that consent.
Verification: VERIFIED.