Is Portal DEX safe?
Portal is medium risk. Opening the Rafa AI exchange view in Portal DEX renders an iframe at extension.rafa.ai whose URL includes your wallet address. It posts a fixed exchange token to it after init. Testing found no live navigation, but the code has both paths.
Who publishes itTides Network, Inc. - no other listings under this identity, 4 shared hostnames
Tides Network, Inc. - no other listings under this identity, 4 shared hostnames
What this publisher told the store about itself, and the other listings that told it the same thing.
Shared hosts - 4 hostnames
Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Swap iframe URL includes the wallet address
Opening the Rafa AI exchange view in Portal DEX renders an iframe at extension.rafa.ai whose URL includes your wallet address.
It posts a fixed exchange token to it after init.
Testing found no live navigation, but the code has both paths.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Dynamic sandbox
You open the Rafa AI exchange view inside the Portal DEX popup.
The route is protected and renders the Rafa AI page only after the wallet is ready.
The extension builds a rafa.ai iframe URL using your active wallet address.
After the iframe reports that it initialized, the component posts a fixed exchange token to it.
- Your wallet address0x742d35Cc6634C0532925a3b844Bc454e4438f44e (illustrative)
This can identify the blockchain account you are using in the extension.
- Exchange integration namep2b
This tells the remote iframe which partner integration opened it.
- Exchange tokenNF5jGzD9vRbL7kPqW8sXzA==
This fixed token is sent to the iframe after it reports that it initialized.
- Network connection metadataBrowser request to extension.rafa.ai (illustrative)
The remote host can receive normal connection metadata when the iframe navigation occurs.
The request body is omitted because iframe navigation uses a GET and no body was recorded.
The popup code builds the iframe URL from the active wallet address
Source-mapped environment constants
src/core/env.tsRAFA_EXCHANGE_NAME: getEnvVar(process.env.RAFA_EXCHANGE_NAME, 'p2b'),RAFA_EXCHANGE_TOKEN: process.env.RAFA_EXCHANGE_TOKEN,Source-mapped RafaAi component
src/entries/popup/pages/rafaAI/RafaAi.tsxconst RafaAi = () => { const { isSidePanelOpen } = useSidePanel(); const { address } = useAccount(); const iframeRef = useRef(null); const [sessionToken, setSessionToken] = useState(null); const exchange_name = env.RAFA_EXCHANGE_NAME; const exchange_token = env.RAFA_EXCHANGE_TOKEN; const sendToken = () => { const message = { source: exchange_name, token: exchange_token, type: 'register', }; iframeRef.current?.contentWindow?.postMessage(message, '*'); }; useEffect(() => { const handleMessage = (event) => { const data = event.data; if (data?.source === 'extension' && data?.type === 'status') { switch (data.status) { case 'initialized': sendToken(); break; case 'authorized': setSessionToken(data.session_token); console.info('RAFA session authorized'); break; case 'error': console.error('RAFA error:', data.error); break; default: console.warn('Unknown status:', data.status); } } }; window.addEventListener('message', handleMessage); return () => window.removeEventListener('message', handleMessage); }, []); if (!address) return null; return (_jsx(Box, { style: { height: isSidePanelOpen ? 'calc(100vh - 80px)' : '520px', overflow: 'hidden', backgroundColor: 'white', }, children: _jsx("iframe", { id: "rafa-extension-frame", ref: iframeRef, src: `https://extension.rafa.ai/${exchange_name}/${address}`, style: { width: '100%', height: '100%', border: 'none', color: 'white', }, title: "rafa-ai" }) }));};- extension.rafa.ai
Receives the Rafa AI iframe navigation whose path contains the exchange name and the current wallet address.
What it can do
Permissions this extension asks for, as declared in version 0.1.28. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Read and change your data on every site you visit
http://*/* and 1 more
Read and change your data on every secure site you visit
https://*/*
Act on the current tab, but only after you click the extension
activeTab
Run its own code inside the pages you visit
scripting
Store data in your browser
storage
See the address and title of every tab you have open
tabs
Store an unlimited amount of data in your browser
unlimitedStorage
Show a panel beside the page
sidePanel
Add items to the right-click menu
contextMenus
Show you desktop notifications
notifications