The recent Upbit incident highlights something that most crypto platforms often fail to consider, crypto deposits security.
While we often focus on the security of private key storage and access for withdrawals, crypto deposits often introduce as much, if not more, complexity and attack surface than withdrawals.
In this post, we’ll dive into the various security touchpoints of a centralized exchange, noting that many of these are applicable to self-custodial wallets, on and off-ramp systems, and other applications handling incoming deposits.
Here’s an example of what a deposit management flow can look like for a central exchange platform.
Note: individual backends will differ. We’ve split out common various functions for completeness:
First, let’s summarize what happens in the “happy path” for most systems:
- Blockchain node (either provided by a 3rd party, or running in-house) detects a deposit to a user’s account on-chain
- Node infrastructure sends event to central exchange backend for processing
- Central exchange backend performs internal checks for compliance (e.g., sanctions screening), correctness (e.g., not processing a duplicate event), and other business logic (e.g., is this token supported on the exchange?)
- If all checks are deemed good, the system can increase the user’s balance on its internal ledger system and notify the user
Throughout the flow, there are many ways things can go wrong including:
- Compromise of the node provider
- Insertion of a fake event in the deposit event manager
- Processing duplicate deposit events without idempotency
- A compromised user wallet manager providing a hacker’s wallet to deposit to
- A bug in the ledger crediting the wrong balance
We’ll dig into each class of weaknesses in more detail below, and how to mitigate against them.
Common Weaknesses & Mitigations
Example: Compromise of the node provider or node client SDK.
Impact: Attackers can withhold events to prevent user deposits as a denial of service, or inject invalid events to cause incorrect balance increments to wallets. This attack vector is applicable to nearly all systems handling deposits, including non-custodial wallets and on and off-ramp systems.
- If using a 3rd party service: perform a security review for your own due diligence and continuously monitor their status
- If using your own node: ensure you’ve locked down access to the node and continuously monitor its runtime environment (ex: unexpected SSH into the machine, redeploys, etc)
- Independently verify incoming events with a separate node client
- Vendor software dependencies into your own repository pinned by hash rather than version, preferably in a signed format
Deposit Event On-chain Transaction Verification Bugs
Example: On-chain event is not applicable to system or environment (ex: not a real user’s wallet, unsupported token or type of event).
Impact: Attackers can cause the system to incorrectly increase balances in unexpected ways – this is where Upbit was vulnerable, and in their incident how fake ”APT” tokens were then treated as real ones and credited to user balances.
- Ensure all meaningful properties of an incoming event are verified with what should be authorized in the system. Here’s a non-exhaustive list:
• Token type (often specified by contract address)
• Token precision / decimals (this check in Upbit limited the blast radius of the attack)
• Transaction type (ex: smart contract call vs transfer)
• Signature verification (If you have access to the full transaction)
Deposit Event Off-chain Verification Bugs
Example: Valid on-chain event is sent twice.
Impact: If idempotency checks aren’t in place, attackers can trigger a replay attack to continuously increase balances of off-chain internal state that does not correctly reflect on-chain state.
- For every incoming transaction, ensure your system checks against unique and immutable properties of the transaction so that it isn’t processed twice. For most blockchains, transaction hash will suffice. Or sending address + nonce/sequence number
- Ensure the system that tracks for replay attacks is monitored closely so its state cannot be wiped in an unauthorized fashion, which would then make the replay attack check useless
Internal State Compromise
Example: Compromise of the user wallet database overwriting wallet users’ IDs with hacker’s user ID.
Impact: Redirect legitimate deposits intended for users to a hacker's account, resulting in financial loss for the legitimate user and platform at the benefit of an attacker.
- Record and audit read-only records of event processing across the system to understand when and where the attack happened as well as the blast radius of impact, and enable the ability to recover from it
- Implement reconciliation and security scanning systems that pick up system and application-level anomalies with the ability to automatically freeze any further action until the system is back to a safe state
Event Integrity Breach
Example: Insertion of a fake event that deposits funds to a hacker’s wallet.
Impact: Fake events cause incorrect balance increments to wallets, despite no event ever occurring on-chain, or a bypass of critical security & compliance checks.
- Implement tight Access Controls for employees and automated systems to: production system, CI, deployment systems & accounts, system configuration management, code repositories and everything else that can lead to code & configs getting to production
• For this particular scenario: ensure that events can only be ingested directly from the intended node provider, not any out of band system
- Each service should have mutual TLS authentication in place with all the other services it interacts with, and the infrastructure should be configured (via service mesh, etc), such that each service can only communicate with the specific services and endpoints it needs to
- System components should verify the integrity & intent of upstream components: a ledger service should verify the integrity & intent of request from the node provider, the deposit manager, and the user wallet manager before processing a deposit
Unknown Unknowns – mitigating other weaknesses
Every system is different, and often it’s difficult to fully threat model your own system,so we’ve added an “unknown unknowns” category to highlight a number of best practices that will mitigate attacks that are often overlooked.
- Use the principle of least privilege to document and limit access per employee and system to the bare minimum of what’s needed – this means that if a attacker gets access, they aren’t given extraneous permission
- Implement mandatory authenticator or hardware-based MFA for all employees – this makes it difficult for an attacker to get access to internal systems (even if they’ve phished an employee’s password)
Last words: Get in touch!
These are just some of the most common weaknesses to consider when managing crypto deposits. Due to the irreversible nature of blockchain, it’s especially important to identify and implement mitigations to avoid non-recoverable security incidents resulting in lost funds.
If you’re building a solution that requires the management of fungible and non-fungible tokens, get in touch at https://www.bastion.com/see-bastion.
Bastion is making it easy, secure, and compliant to not only create user wallets but also manage their web3 experiences and assets at enterprise scale!