27 November 2023

Uncovering Vulnerabilities: Decoding the Off-chain Code of Blockchain Bridges

My name is Kyryl Volkov and I'm one of Cyrex' resident security engineers. In this blog post, I'll take you through and discuss 2 critical vulnerabilities in the bridge backend I discovered during one of our security assessments in Cyrex. 

These vulnerabilities allow malicious actors to steal all funds from the bridge. It was a typical [burn & mint] bridge, where we have contracts on each blockchain and off-chain code, which burns or mints the funds. Let's go over which assets we have:

  1. Frontend with JS code which creates transactions users sign.
  1. Contract deployed on the Ethereum network.
  1. Contract deployed on Solana network.
  1. Backend off-chain code that processes transactions.

Hack 1 - Stealing Hashes

Typically, burn and mint functions emit events that the off-chain bridge code listens to in order to transfer funds between blockchains. However, in this case, it was different. When users lock their funds, the browser sends a request to the backend server with the following JSON:

Usually, as users, we do not have direct access to the off-chain server, as it automatically listens to new events. However, in this case, the developers relied on users sending such requests to the server. Let's step aside and examine the events emitted by regular burn and mint functions:

These fields are critical for validating the trustworthiness of the transaction. Without the `to` field, it becomes challenging to identify the recipient on the target blockchain. Now, let's see how the event looks in this case:

That's it. They didn't specify the recipient of the funds. This, combined with our `POST /txs/eth` request, allows us to take the `txHash` of another user and use it before the regular user submits it. We can listen to new events or even transactions in the [mempool] and flood the server with the new hash before the legitimate user submits it.

Hack 2 - A Difficult Case

Obviously, we tried to replay the same transaction several times, but it did not work. You may wonder how the backend identifies which transactions are processed and which are not, especially when the event does not contain a date or nonce field. The developers decided to write them to the off-chain database. MongoDB, to be precise.

One of the first ideas that came to my mind when I saw that HTTP request was if I can somehow replay an old transaction hash by, for example, adding spaces, adding/removing `0x`, adding extra zeros, using Unicode characters or specifying an array where the same hash is repeated numerous times. Actually, I even tried generating thousands of variants of `txHash` using [radamsa], a general-purpose fuzzer.

As you may have guessed, it was much easier. We could just change the case of any character in the `txHash`.

* Original txHash: `0x0123456789abcdef0123456789abcdef01234567`

* Custom txHash: `0x0123456789abcdef0123456789abcdeF01234567`

Why did that happen? Looking into the source code revealed that developers were using the `findOneAndUpdate` function. It is not specified directly in the documentation, but this function, as well as most of the operations in MongoDB, is case-insensitive.


While browsing through sources, we identified another 2 endpoints, `POST /start-bridge` and `POST /stop-bridge`. As it turned out, they did not have authentication and anyone could send requests, which would pause the bridge backend.


To ensure the security of bridges between different blockchains, it is crucial to follow best practices and implement the following recommendations:

  1. Do not expose the bridge backend to users; let it listen to blockchain events.
  2. Design events with essential fields for proper transaction validation.
  3. Avoid storing processed transactions in off-chain databases.
  4. Implement strict validation to prevent replay attacks and manipulate hashes.
  5. Apply strong authentication and access controls to all endpoints or do not expose them.
I hope by adhering to these recommendations, bridge developers can enhance the security of their bridges and the safety of their clients. It is vital to prioritize security throughout the development and deployment lifecycle of blockchain bridges to maintain trust and confidence in the decentralized ecosystem.

If you’re interested in utilizing the experience and expertise of our security engineers, why not get in touch with us today for any of your penetration testing or load testing needs? We’re the gold standard and guarantee only the best results.