Is Revoke.cash - web3 scam protection safe?
Revoke.cash - web3 scam protection is high risk. Starting a wallet transaction or signature request, the content script forwards details to the SW, logged as "Message received". Details can include addresses, calldata, signature data, chain ID, hostname, a user ID. Evidence is code-based.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Wallet messages are forwarded to Amplitude analytics
Starting a wallet transaction or signature request, the content script forwards details to the SW, logged as "Message received".
Details can include addresses, calldata, signature data, chain ID, hostname, a user ID.
Evidence is code-based.
You start a protected wallet action on a website.
The covered requests include transactions, typed signatures, personal-sign messages, wallet_sendCalls, and Coinbase wallet signing requests.
The extension forwards the wallet request details to its service worker and labels the full object as analytics.
The service worker calls the tracking helper with a Message received event whose message property is the original wallet-message object.
| Field | Value | Why it matters | |
|---|---|---|---|
Website hostname | app.uniswap.org (illustrative) | Shows which site you were using when the wallet request was processed. | |
Wallet request type | eth_sendTransaction (illustrative) | Shows what kind of wallet action you were asked to approve or sign. | |
Wallet address fields | from=0x742d35Cc6634C0532925a3b844Bc454e4438f44e, to=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 (illustrative) | Can identify which wallet address was involved in the request. | |
Transaction calldata | 0x095ea7b30000000000000000000000001111111254eeb25477b68fb85ed929f73a9605820000000000000000000000000000000000000000000000000000000000000000 (illustrative) | Can reveal the contract method and parameters behind the action you were asked to approve. | |
Signature message content | personal_sign message: Sign in with Ethereum to app.uniswap.org (illustrative) | Can include the message or typed data you were asked to sign. | |
Persistent extension user ID | f3a742c1-8e10-44d2-bc6a-9d5e0c2a7814 (illustrative) | Lets analytics associate separate wallet-message events with the same extension installation over time. |
The content script packages wallet requests with hostname and chain ID
const os = (e, t) => {
const n = as(t);
e.postMessage({
requestId: n,
data: t
})
};
let is = 0;
const as = e => {
const t = ++is;
return e.type === ns.TRANSACTION ? ss()({
...e.transaction,
_nonce: t
}) : e.type === ns.BATCH_TRANSACTION ? ss()({
_batch: e.transactions,
_nonce: t
}) : e.type === ns.TYPED_SIGNATURE ? ss()({
...e.typedData,
_nonce: t
}) : e.type === ns.UNTYPED_SIGNATURE ? ss()({
_msg: e.message,
_nonce: t
}) : ss()({
...e,
_nonce: t
})
};
let cs = 1;
const us = !0;
window.addEventListener("message", e => {
const {
target: t
} = e?.data ?? {}, {
name: n,
data: r
} = e?.data?.data ?? {}, {
hostname: s
} = location, o = cs;
if ("metamask-provider" !== n || !r) return;
const i = e => {
Array.isArray(e) ? e.forEach(e => {
if (e)
if (ls(e, "eth_sendTransaction")) {
const [t] = e.params ?? [], n = ns.TRANSACTION, r = es().runtime.connect({
name: ts
});
os(r, {
type: n,
bypassed: us,
hostname: s,
transaction: t,
chainId: o
})
} else if (ls(e, "eth_signTypedData")) {
const [t, n] = e.params ?? [], r = JSON.parse(n), i = ns.TYPED_SIGNATURE, a = es().runtime.connect({
name: ts
});
os(a, {
type: i,
bypassed: us,
hostname: s,
address: t,
typedData: r,
chainId: o
})
} else if (ls(e, "eth_sign") || ls(e, "personal_sign")) {
const [t, n] = e.params ?? [], r = 40 === String(t).replace(/0x/, "").length ? n : t, o = ns.UNTYPED_SIGNATURE, i = es().runtime.connect({
name: ts
});
os(i, {
type: o,
bypassed: us,
message: r,
hostname: s
})
} else if (ls(e, "wallet_sendCalls")) {
const [t] = e.params ?? [], {
from: n = "0x0000000000000000000000000000000000000000",
calls: r
} = t ?? {}, i = ns.TRANSACTION, a = es().runtime.connect({
name: ts
});
for (const e of r) {
const t = {
from: n,
...e
};
os(a, {
type: i,
bypassed: us,
hostname: s,
transaction: t,
chainId: o
})
}
}
}) : i([e])
};
"metamask-contentscript" === t && i(r), "metamask-inpage" === t && r?.method?.includes("chainChanged") && (cs = Number(r?.params?.chainId ?? cs))
}), window.addEventListener("message", e => {
const {
type: t,
data: n
} = e?.data ?? {}, {
hostname: r
} = location;
if ("extensionUIRequest" === t && n) {
if ("signEthereumTransaction" === n.request?.method) {
const e = {
from: n.request.params.fromAddress,
to: n.request.params.toAddress,
data: n.request.params.data,
value: Number.parseInt(n.request.params.weiValue ?? "0").toString(16)
},
t = Number(n.request.params.chainId ?? 1),
s = ns.TRANSACTION,
o = es().runtime.connect({
name: ts
});
os(o, {
type: s,
bypassed: us,
hostname: r,
transaction: e,
chainId: t
})
}
if ("signEthereumMessage" === n.request?.method) {
const e = n.request.params.typedDataJson,
t = n.request.params.address;
if (e) {
const n = JSON.parse(e),
s = Number(n?.domain?.chainId ?? 1),
o = ns.TYPED_SIGNATURE,
i = es().runtime.connect({
name: ts
});
os(i, {
type: o,
bypassed: us,
hostname: r,
address: t,
typedData: n,
chainId: s
})
} else {
const e = n.request.params.message,
t = ns.UNTYPED_SIGNATURE,
s = es().runtime.connect({
name: ts
});
os(s, {
type: t,
bypassed: us,
hostname: r,
message: e
})
}
}
}
});
const ls = (e, t) => String(e?.method)?.toLowerCase()?.includes(t?.toLowerCase())The service worker tracks the whole message object
var zo, Do = Bo.init,
Oo = Bo.track;
const ac = () => Boolean("20f100b65efa90a8e1511c26488a4a83") && !0;
(async () => {
if (!ac()) return;
const e = await vs("sync", "user:id");
Yo = e ?? (() => {
let e = () => Math.floor(65536 * (1 + Math.random())).toString(16).substring(1);
return e() + e() + "-" + e() + "-" + e() + "-" + e() + "-" + e() + e() + e()
})(), e || await (async (e, t, n) => {
await r().storage.sync.set({
[t]: n
})
})(0, "user:id", Yo), Do("20f100b65efa90a8e1511c26488a4a83", Yo, {
trackingOptions: {
ipAddress: !0
},
flushQueueSize: 1
})
})();
const ic = (e, t) => {
ac() && (Oo(e, t), ec(e, t))
}ry = e => {
Of.includes(e.requestId) || (Of.push(e.requestId), ic("Message received", {
message: e
}))
}- api2.amplitude.com
Amplitude HTTP API endpoint embedded in the SDK; dynamic analysis captured POST traffic to this host.
- api.eu.amplitude.com
Alternate Amplitude HTTP API endpoint present in the bundled SDK endpoint selector.
- api.fairside.io
Extension backend endpoint used by the same tracking helper's queued event flush path.