Do not open a public issue.
Use GitHub's private vulnerability reporting: the Security tab → Report a vulnerability. It opens a private thread with the maintainers, and it is the only channel that gets you a response before the details are public.
Please include:
- which component — the router contract, one of the SDKs, or the quote service
- what an attacker gains, concretely (funds at risk, wrong quote, denial of service)
- a way to reproduce it: for the contract, a
forgetest against a mainnet fork; for the SDKs or the API, the pair, amount, trade type and block number, since a quote is only reproducible pinned to a block
You will get an acknowledgement, and we will tell you what we intend to do and roughly when. If we disagree that something is a vulnerability we will explain why rather than going quiet. Please give us a chance to ship a fix before publishing.
| in scope | |
|---|---|
UniversalRouter at 0x691e…F6A6 and the source in packages/universal-router |
funds at risk, unauthorised callbacks, slippage limits that do not bind, command dispatch flaws |
The published @topazdex/* packages |
calldata that does not do what the trade says, slippage or deadline encoded wrongly, quote maths that disagrees with the chain |
quote.topazdex.com |
quotes that are wrong in a way an attacker can steer, calldata that pays out to the wrong address, anything that lets one caller deny service to others |
Out of scope, because they are known and documented rather than undiscovered:
- No rate limiting on
quote.topazdex.com. It is public and unauthenticated, and each quote is ~16eth_calls against public RPCs. One script can degrade it. This is a known operational gap, tracked inCLAUDE.md; reports that it can be hammered are not new information. - Fee-on-transfer tokens are not modelled. Quotes price the pool maths, not a token's transfer
hook, so the received amount for a taxing token can breach
minimumAmountOut. Documented indocs/FRONTEND_INTEGRATION.md. - Stale quotes revert. The deadline and slippage limit are baked into the calldata at quote time. A quote left on screen expiring is the intended behaviour.
- Third-party infrastructure: BNB Chain itself, Permit2, public RPC providers, the subgraphs.
- Reports produced by a scanner with no demonstrated impact.
Worth knowing before you spend time on a report:
-
It is immutable. No owner, no proxy, no upgrade path, no admin functions. Its parameters are baked into the runtime code at deploy. There is no privileged role to compromise.
-
It holds no funds between transactions. Every command sequence ends by paying out, and
receive()is restricted to WBNB so stray BNB cannot be parked in it. A balance sitting in the router mid-transaction is spendable by the rest of that transaction only. -
The deployed bytecode is this source, byte for byte — asserted by
DeployedRouterForkTestand verified on BscScan. You can check it yourself:cd packages/universal-router DEPLOYED_UNIVERSAL_ROUTER=0x691e6171e0a434FfE5C9f1759621D05b9efcF6A6 forge test
None of that makes it correct — it means a vulnerability here is a logic flaw in the command set or the pool maths, not a key-management or upgrade problem.
The npm packages are at 0.1.0 and only the latest release is supported. There is one deployed
router; because it is immutable, a fix to the contract means a new deployment and an updated address
in UNIVERSAL_ROUTER_ADDRESSES, not an upgrade.
Frontends should take the router address from the to field of the quote response rather than
hardcoding it, so an address change does not require a release on your side.