Common Security Issues in Crypto Wallets
DeFi Security Summit at Devconnect Argentina 2025 · November 2025 · 23:54
Jahyun Koo, senior security researcher at Hexens, describes the recurring weaknesses of crypto wallets, which are the critical gateways for DeFi users. The talk outlines common security issues across browser, mobile and web wallets, illustrates them with real audit findings and gives guidance on effective mitigations for wallet developers and the teams that review their code.
Speakers
Topics
From DeFi Security Summit at Devconnect Argentina 2025, hosted by DeFi Security Summit.
Transcript
ions in crypto gateways uh common security issues in crypto wallets especially uh based on the fact that they are now the gateways towards web three for most of the users. So Angie please go ahead. >> Hi everyone. I'm Andy from Hex. I'm a security researcher and yeah today I'd like to walk you through about uh the uh some some of security issues that uh we are why we are doing multiple uh wallet audits and yeah um before I started uh please uh uh I I
appreciate your patience in my English my my English is not perfect but yeah let me start uh yeah the those the problems are not just simple bugs uh but many of them are from architecture choices uh misunderstandings of about the browser or mobile environment or the way of wage are uh interact with the outer component So yeah in this talk I will go through concrete examples to show how this we need emerging and why they are matter and what we can do to build more safer
uh wallet design. Okay. Uh let me start with the threat vector. So there are three major threat vectors for wallet and it's um the first one is the obviously uh web pages and devs and and they can send post messages and sometimes they soops their origins or trigger wallet pools without users uh noticing it or hide their real identities. And the second the physical access attacker uh someone with access to the user's device could and they can
dump memory or brute post weekly drive the password using the K uh uh weekly W KDF and also they can temper OS level secure storage and the third is the user themselves And it's not about the they making a bad decision on their trading and it's about the user may approve misreading UI and and mal and they can add malicious network or interact with the transactions uh that hides the critical issues.
So this is the structure of extension wallet. Uh it is simplified version and uh web page first interact with the wallet through a provider and which is uh this provider is the interface that exposes uh methods like uh Lucas uh me like Lucasing account or asking asking for signatures and The provider doesn't learn any logic on its own but it ports everything to the last of the wallet
and those those request go to the content script and which act as a middle layer inside the browser environment. The content script cannot access sensitive wallet data directly. So its job is just uh passing messages along and the actual decision making happens in the background script. The this part of the wallet uh verifies the request and applies the required checks and learns all sensitive operations
such as signing transactions or managing accounts and adding networks. And this separationless dep communication with the wallet while keeping the critical logics isolated in the background layer and it is more complic uh somewhat more complicated design but uh it's the same some extension wlet let's use use service workers and or additional uh components
uh two separate tasks like uh networking storage or signing and even with this extra component the communication flow is similar. Uh the web page talks to provider. The content script layers relates the request. The background layer coordinates the logic and the extra workers uh simply extend this pipeline helping uh the wallet organize it picture while keeping sensitive operations isolated from the web page.
And the mobile wallet uh follows a different architectures but they have their own unique unique list. Instead of instead of a post message, they primarily receive external requests through URI or intent filters and internally they pass the the the input of URI and and intent filters and they update the UI and they rely on native implementations and secure the storage APIs such as uh in iOS keychains
and on in Android shared preferences and if the wallet doesn't strictly validate what it passes and at the beginning of the flow and even a simple dim link dim link can trick it into executing uh malicious signings or connecting to an intended network. So while the technologies differ from extensions, the co the core requirement is the same. Uh statically depends the the input passing.
Yeah, it is the first major vulnerability category is the message type validation. Uh in extension wallet uh the post messages uh the post message calls and uh uh similar IP communication are not used by only by the user or web page but uh each external uh I mean each internal component also uh use this post message and IP call. So wallet can also send messages to others as part of normal operation and because of this the wallet cannot
assume that any incoming message co message is safe. Every message needs strict checks on its structure and type and all field. And if the wallet simply accept any object with the type and an attacker could craft a message that trigger internet PS, bypass UI checks or invoke operations that they were not meant to be exposed. And here is a simple example from a from common wallet flow. When uh dev tries to
uh send users tokens, then the wallet checks the current network. If the current network is not matched with the uh uh the the sorry matches the wallet's current network is not the matches with the depth network then uh the wallet opens the change network UI and screen before anything else happens. uh once the user confirms that steps the UI sends a message to to continue the pool and the next screen the the actual token transport confirmation
appears. So this this shows that uh multiple UI steps are chained together through internal message and because this transitions rely on message passing between components, the wallet needs to validate each message carefully to ensure the pull isn't alled or triggered unexpectedly. Okay. When message travels across different part of the wallet, the background script has to know exactly where each message is coming from. Some me some messages originate from uh uh
that through content script and others come from internal UI component. If the wallet doesn't clearly distinguish between those two sources, the background script cannot reliably decide which message represent user approved actions and which one comes from an untrusted web pages. And this ambiguity makes possible for wrong type of messaging to advance the flow or trigger UI.
That was never meant to happen. And this diagram shows the flow of how a transaction signing request moves through the wallet. So if users uh send the post message through the content script, then the handler of this request shows the UI of to confirm the user's approval. But uh at this point the wallet uh when the user composs the transactions another inter another intern message triggers the next handler and the the handle the second handler
and this leads to actual signing implementation and yeah. Yeah. Finally, the signed transactions is sent out to the RPC server to be broadcast to the network. Yeah. So if the wallet does not strictly verify where messages are coming from, not attacker can bypass this steps entirely uh by sending crafted messaging directly to the background script and they can trigger the the second handler without ever showing the approval UI.
In other words, the wallet ends treating a poor message as if a user already reviewed and approved the transaction allowing the pro to jump straight into the signing implementation. And the next issue is origin validation. Uh in extension wlet both the top level dev and any Ira inside it can send post messages to the content script but post messages uh there's a field saying is the origin field is just part of the
message. So it is not uh the reliable source of origin. So so malicious I frame can simp simply spit and in the in the example here the main site and the embedded Ira both communicate with the content script. And if the wallet lies only on the origin origin value inside the message, the content script cannot tell whether the pulley came from top level of web page or from the malicious I pray pretending to be it.
uh in this in in this example uh if you can see uh right there uh the the I frame on the page is able to send post message to the content script and inside the message it can preet the origin field to whatever it wants and here it claims to build devxy if the wimp Simply to this value, the UI UI will display the wrong requesting site and making uh the PCing attempt uh look like legitimate
to to validate origins correctly. Uh the wallet should never trust the origin values of the post message and instead uh message must be validated using the read only uh browser provided message event source. uh if the source doesn't match the current window. For example, if it comes from I frame or different browsing context, the message should not be processed and the wallet should also check the origin against the all list of trusted
domain. This prevents hidden hidden frames, pop-ups or of screen tabs from injecting privileged messages. Yeah, it is a origin visibility issues and even if wallet verifies the origin correctly, uh user still depends on the UI to confirm which side which site is making the lest but attacker can manipulate how the origin is displayed. They can inject uh invisible paddings or generalist
character by reactional characters or homoges that look identical to normal letters. And this makes the malicious domain appear visually identical to a trusted on trusted one and even though the underlying code points are completely different. Yeah. And in this example, the second one uh the the truncation hides the most important part of the origin. This makes it even easier to miss with user because they cannot see the pool domains and cannot spure
tricks. And to avoid this text, wlet must sanitize and normalize the origin strings and also display it in pool without truncation. And the both issue is about the network addition. when dev as a new network manual. Let's patch metadata such as uh chain ID directly from RPC endpoint. Uh this code looks uh checking the chain ID from the user
provided chain ID but it simply compares the ID returned from the RPC endpoints. So if the end point is controlled or modified by attacker, this comparison will always succeed because user provided chain ID is also provided by malicious RPC endpoint and the actual duplication check uh is only performed on the network uh this name and URL.
So this means a manage endpoint can still provide it the uh can still provide the duplicated chain ID and the wallet will accept it as as long as the name or URL doesn't complete with an existing entry. Yeah. So if this happen the wallet may appear to be interacting with familiar chain but all RP data is actually coming from an attacker control server. As a result the the wallet could display incorrect balance and show fake transaction history or with little
manipulated guess estimation. And furthermore, the attacker can front or back the user's transaction before broadcasting it. And it is a difference between a safe and unsafe flow of signing transaction. The unsafe version recies from pro from the RP servers. Uh so if the if the endpoint returns a manipulated chain ID, the wallet generates a signature that is perpetually valid. But for a different
network, the attacker could exploit this in a way that leads to depth or unauthorized approval. The volume most rely on user configured chain ID never dynamically patch it once. And the fifth one is the fragile P of token UI and can you find what is what information uh missing in this uh token UI? Uh uh in token specific UIs like this one.
many of those fields are missing. Uh for example, there is no message value uh shown at all. So the user has no way to verify whether an is value transfer has been included alongside the token transfer. And this happens because token transfer page often use a different UI than the wallet pool side transaction view. Thank you so much. Uh time is up. If you can wrap it up in 30 seconds, that would be awesome.
>> Uh yeah. Uh this one is so much fun. So I I'd like to introduce uh so this diagram shows how a minimal incomplete UI can lead to real attack. Uh the user visit the valicious rotary website. The site first checks the user's balance to the provider. The website then sends the user a small amount of malic malicious USDT like tokens and next the user is prompted to transfer one unit of that USDT tokens in the UI. This looks harmless and it
appears to be standard ERC20 transfer but the contract behind this token is uh designed so that it transfer function is payable and when the user signs the transaction the website attaches a large MS value even though the UI never show it and as soon as transaction is executed the contract trains hold the is value of users. So showing the whole informations of transaction is very crucial in this uh yeah
in wallet design and also we have a uh we build uh this is why we build a token risk API because it analyzes tokens across many chains. and provides a clear easy to understand signals about whether token BFC in a way that we flag the uh we can you can pl the tokens that are interacting with users and with this uh extra layer of the wallet
uh the wallet becomes more than a place to sign transaction uh it helps user understand what they are dealing with and reduces the chance of approving something harmful without realizing it. And yeah, my talk has more content, but I I think I need a wrap up this time. And yeah, thank you very much. >> Thank you. Round of applause.