Railgun Deep Dive Addendum: #REKT
Final Analysis: Security Theater for the User & Treachery for the Operator
Prelude
When I began this series exploring various blockchain privacy solutions, I was especially drawn to Railgun due to my long-standing interest in the Ethereum Virtual Machine—and because I had a personal stake in the project as an operator of a Railgun relay. I wanted to take a deeper look at the Railgun protocol to answer a few questions of my own, such as: How does Railgun differ from Tornado Cash? I also aimed to provide a general analysis and explanation of how the protocol works, to help others make use of Railgun for enhancing their on-chain privacy.
Prior to writing this series, I had been operating a Railgun relay for about six months—for personal enjoyment and profit. The experience, while occasionally frustrating (largely due to an unhelpful community), was overall quite rewarding. I did manage to turn a profit, which led me to recommend a new venture to one of my clients—my favorite client, in fact. The proposal: launch a new business together and run a Railgun relay. At the time, it felt like a smart move.
My reasoning was simple. I already manage several servers for this client that host various blockchain-related applications, and he’s always been open to expanding into more niche and experimental areas of the ecosystem. We’ve long shared a mindset of exploring blockchain technologies that are both interesting and potentially profitable. Over the years, we’ve debated operating all sorts of nodes and services—from Ethereum staking to briefly considering a Solana validator. In short, we’re always on the lookout for blockchain-based applications with revenue potential.
Given my passion for online privacy, blockchain tech, and the EVM—and the fact that I had already made consistent profits from a personal Railgun relay—this seemed like the next logical step. After discussing the idea, my client agreed. We spun up a new server, deployed a relay, funded it with $2,000, and got ready to sit back and watch the profits roll in.
Background
For those unfamiliar with Railgun—or if you haven’t read the earlier segments of this series—here’s a quick overview of how it all works.
What Is Railgun?
Railgun is a smart contract system that enables private cryptocurrency transactions on public EVM-compatible blockchains. Currently, it supports Ethereum Mainnet, Binance Smart Chain (BSC), Arbitrum, and Polygon.
In practice, Railgun functions similarly to the previously-sanctioned Tornado Cash system—despite the developers’ insistence that it “is not a mixer.” I addressed and debunked that claim in detail in the previous post, Railgun Deep Dive Part II.
Public vs. Private Wallets
Public Balance: This is what most crypto wallets expose—your tokens, transaction history, and wallet activity are all publicly visible on the blockchain.
Private Balance: With Railgun, you can shield assets by moving them into a private vault. Once shielded, your holdings, transaction history, and recipient addresses are hidden from public view.
Railgun wallets operate like standard hierarchically deterministic (HD) wallets. A mnemonic phrase generates an unlimited number of public addresses, all linked to a single private vault. This allows for seamless interaction between the public and private layers.
The Role of Relays
Here’s how shielding and relays come into play:
A user sends assets to a public address derived from their mnemonic.
They then shield those assets by sending them into the Railgun smart contract, which credits their private balance.
The same smart contract is used by all users on the same chain—this shared pool is a critical reason why I reject the "not a mixer" label.
When it's time to unshield assets (i.e., move funds back to a public address), users have two options:
Self-broadcast the transaction: This is cheaper, but requires the user to fund a public wallet with native tokens (ETH, MATIC, BNB, etc.) to cover gas fees.
Use a relay: The relay submits the transaction on behalf of the user and pays the gas fee. In return, the relay earns a small commission—typically around 20% of the transaction’s total fee.
This model removes a major friction point: needing public funds to move private assets.
Synopsis
Railgun uses relayers to maintain user privacy without compromising usability:
When you send a private transaction, a relay broadcasts it without revealing your identity.
You don’t need native gas tokens—relays cover the transaction fees.
You pay the relay a small fee directly from your private balance.
It enables private, gasless, on-chain activity—much like using cash.
In short, relayers are essential to the protocol. They keep it running smoothly and are compensated fairly for their services.
Smooth Sailing
At first, it all felt like a no-brainer—and for a time, it really was a successful venture. Our relay was running smoothly, handling a steady stream of transactions, and consistently generating a modest but reliable profit. Volume wasn’t astronomical, but it was decent, and we were confident in the system we had built.
A Plot Twist
That all changed on April 7th, 2025.
What had been smooth sailing turned into a shipwreck overnight. (#REKT)
Based on the documentation I had read, I believed that transactions would only be relayed after being validated to ensure they wouldn't revert. That assumption turned out to be critically incorrect.
As shown in the screenshot below, someone discovered a vulnerability in the railgun protocol and used it to repeatedly exploited our relay. The attacker drained the Ethereum balance from our relay’s mainnet public wallet—about 0.5 ETH, or roughly $730 USD at the time.
I was first alerted by a message from my client: “We’ve been attacked.”
I dropped everything and began investigating immediately.
Given my prior experiences with the Railgun development team—where communication had often felt like shouting into a void—I knew I needed to get their attention fast. So, I opened an issue on GitHub and documented the vulnerability publicly. In hindsight, that was a move I would come to regret (more on that shortly).
I also reached out to the developers through their Telegram group. Their response:
Remove the GitHub issue and the associated repository.
Contact us through the official bug bounty program.
At the time, I wasn’t thinking about bounties or rewards—I was trying to alert the team to what I saw as a critical vulnerability that could be used to cripple the entire protocol if exploited at scale.
Later, I found out that if I had instead reported the issue privately via email, rather than documenting it openly, I may have qualified for a bug bounty payout in the range of $125,000 to $250,000.
That realization came after the fact, when I sent them a detailed vulnerability analysis via email. I’ve attached the markdown version of that analysis below.
Incident Regarding ~ $730 of Ethereum drained from my railgun relay.
Issue created here: https://github.com/Railgun-Community/private-proof-of-innocence/issues/31
Synopsis
Starting at Apr-07-2025 at 10:12:47 AM UTC, my railgun relay suffered a series of attacks. Twelve transactions over the course of an hour reverted, costing me about $730, or about .48 Ethereum. The attacks continued until all of my relay's available ethereum was depleted. Upon further analysis, I discovered that the target contract for these transactions was this contract: https://etherscan.io/address/0x87c7f7d6c8e4a358eb798e92574ae129f001d7f5/advanced#internaltx
Reverting contract:
I decompiled the bytecode as the source is not available:
function _SafeAdd(uint256 varg0, uint256 varg1) private { require(varg0 <= varg0 + varg1, Panic(17)); // arithmetic overflow or underflow return varg0 + varg1; } function _SafeMul(uint256 varg0, uint256 varg1) private { require(!varg0 | (varg1 == varg0 * varg1 / varg0), Panic(17)); // arithmetic overflow or underflow return varg0 * varg1; }function fallback() public payable { revert(); }function 0x67658be1(uint256 varg0, uint256 varg1) public payable { require(4 + (msg.data.length - 4) - 4 >= 64); v0 = v1 = 0; while (v0 >= varg0) { v2 = _SafeAdd(v0, v0); v3 = _SafeMul(v2, 2); require(2, Panic(18)); // division by zero v0 = v3 >> 1; v0 += 1; } require(varg1 >= block.number); }// Note: The function selector is not present in the original solidity code. // However, we display it for the sake of completeness.function function_selector( function_selector) public payable { MEM[64] = 128; require(!msg.value); if (msg.data.length >= 4) { if (0x67658be1 == function_selector >> 224) { 0x67658be1(); } } fallback(); }
Obviously this contract is designed to burn gas and then revert. I am surprised that railgun processed this transaction, as I was under the impression that railgun would not process a transaction that would revert. It goes without saying why that must be the case for us relayers. I am not operating a relay until this is fixed or I can figure out how to prevent it from happening again, that's for sure.
Contract call trace
https://pastebin.com/YKpJU5aN
Prevalence of this problem
Take a look at the contract's internal message calls and you'll see I am, at least to my knowledge, the third victim that the operator of this contract has hit. This is a serious problem that must be patched immediately. It is extremely risky to run a relay under these circumstances. Contract calls that burn a bunch of gas and revert will sabotage relay operators. My client just lost almost half an ETH. I am annoyed. Not going to lie. Had I known that all of my client's money could be siphoned, I would not have recommended running this relay. And I don't know how often this has happened, but I imagine more than just 3 times with other contracts. I will analyze the blockchain and find out and update this repository.
Interesting twist
I think the deployer of this contract is in fact a relay operator. I haven't verified that for sure, but it sure looks that way. [https://etherscan.io/address/0xfacfc25c10ff9e44cf2439dbbec9b20e887d4530](take a look ... )
I am assuming the culprit is trying to take out the competition. If this type of attack is not fixed, the railgun project will fail. If it's not fixable, there needs to be some kind of insurance fund to reimburse rekt operators. But I think it should be fixable. I thought transactions that would fail were rejected. How is that not the case?
Several Realizations
After the dust settled, a number of important things occurred to me.
First, it’s far more likely that the attacker deployed the malicious contract via a Railgun relay, rather than being the operator of the relay that deployed it. In other words, they probably used someone else’s infrastructure to carry out the attack anonymously.
Second, this wasn’t a case of someone trying to eliminate the competition. This was a targeted attack. How can I be so sure? Because it happened again (and other reasons I won’t get into today) —but more on that in a moment.
What’s truly mind-blowing is that the attacker burned a zero-day exploit—one I now believe could easily have earned a $250,000 bug bounty—just to drain $730 from our relay. That’s not opportunistic. That’s sadistic. It also strongly suggests the attacker is well-funded, possibly with institutional or insider knowledge.
After digging deeper, I couldn’t find any prior discussion or disclosure of this vulnerability. I now believe that the two other relays that appeared to be “attacked” months earlier weren’t targets in the true sense—they were most likely tests conducted by the attacker using their own relays to verify the exploit’s reliability. That would make our relay the first and only third-party target ever hit with this vulnerability.
A Grim Conclusion
The entire experience left me with a bitter realization: The Railgun project is not a serious project.
If it were, this exploit—capable of wiping out every single relay operator on the network—would have been treated as a top priority. The fix should have been immediate and the vulnerability patched with urgency. But, as we’ll soon see, that wasn’t the case at all.
One Silver Lining
To their credit, the Railgun dev team did refund us for the first attack. Unfortunately, that wasn’t the end of the story…
Rekt Again
I waited nearly two months before bringing the relay back online. I had seen that at least one of the Railgun smart contracts had been upgraded, and assumed—reasonably, I think—that the vulnerability had been patched. In my defense, I never received a response to the email I sent after the first attack. And, as I’ve already mentioned, my experience with the Railgun developer community has been anything but helpful. At that point, I figured they were just ignoring me—par for the course.
Up until this point, I was still operating under the theory that another relay operator might have been trying to eliminate the competition. After all, why else would someone burn a zero-day exploit potentially worth a quarter million dollars just to rob me of a few hundred? It didn’t add up.
But on May 27th, 2025, that illusion was shattered.
Less than twelve hours after restarting our relay, we were attacked again. That was the moment it became painfully clear: this wasn’t random, and it definitely wasn’t competition.This was personal.
No other relays had ever been hit with this exploit. Just mine. Twice.
Damage Report
This time, I was able to shut things down before the attacker drained the entire balance—but not before they got away with roughly $1,500.
I was stunned. What had the Railgun devs been doing during the two months since I first reported the vulnerability? Clearly, they hadn’t patched it.
To be fair, part of the blame falls on me. I didn’t confirm with the developers whether the issue had been resolved. I simply assumed that the contract upgrade I observed must have been a fix—because why else would they push an update? Especially when this bug had the potential to obliterate the protocol.
But that assumption was wrong.
Radio Silence
I never received a response to any of my emails—not the first one, not the second, not the follow-ups.
Finally, out of frustration, I told them plainly:
“If you don’t at least acknowledge this issue, I will make this story public.”
Still, no response.
The only conclusion I can draw is that Railgun must have backers with very deep pockets. If a large-scale exploit were ever carried out and all relayers were hit at once, the project would either have to refund everyone or risk a complete loss of trust. Either way, it would be a PR disaster.
And yet…
They don’t seem to care — and I find that quite fascinating.
Final Thoughts
I’m publishing this because the community deserves to know the truth:
The administrators of the Railgun protocol do not take the interests of their users or operators seriously.
A responsible team would have:
Patched the bug immediately.
Alerted the community.
Explained what had happened.
Offered guidance to mitigate future risk.
But none of that happened.
Instead, we’re left with silence, risk, and the realization that this is not a serious project, and these are not serious people.
The “Not a Mixer” Myth
Reflecting on this experience, one question keeps resurfacing:
How does Railgun continue to claim it’s “not a mixer”?
And more importantly:
Why was the lead developer of Railgun giving a presentation to a room full of FBI agents, while the lead developer of Tornado Cash sat in a European jail cell?
Technically, the mechanism Railgun uses to break the link between senders and recipients is virtually identical to Tornado Cash. Yet Tornado Cash— despite being sanctioned—offers a more robust implementation.
Tornado Cash enforces standardized input/output amounts (e.g., 0.1, 1, or 10 ETH) to improve privacy guarantees.
zk.money, the now-defunct Aztec project that inspired Railgun’s approach, strongly recommended users follow similar practices.
Railgun, by contrast, makes no such recommendations. There’s no mention in the documentation about how amount correlation can compromise privacy.
That’s not just an oversight. That’s negligence.
Inexperienced users are left vulnerable to de-anonymization techniques from blockchain surveillance firms like Chainalysis—simply because they aren't warned about the risks of using arbitrary deposit and withdrawal amounts.
Why?
Security Theater for Users, Treachery for Operators
This is why I’ve subtitled this post:
“Security Theater for the User and Treachery for the Operator.”
Based on everything I’ve experienced—and everything I’ve learned—I can no longer recommend Railgun for anyone serious about privacy.
Users: There are better, safer options for private transactions on EVM chains.
Operators: Running a relay on Railgun is a high-risk endeavor with little support and even less transparency.
Frankly, I don’t believe anyone acting in good faith could conclude that this team is genuinely committed to protecting its users or ecosystem contributors.
Alternatives Worth Exploring
If you're seeking privacy on EVM-compatible networks, I would recommend looking into projects like:
Tornado Cash – Still one of the most technically sound implementations of on-chain privacy, even in the face of regulatory pressure.
Linea – An increasingly compelling ecosystem with growing privacy tooling and active development.
As discussed in previous parts of this series—and as highlighted by the story in this post—it’s unwise to rely on a single protocol for privacy.
For example, Tornado Cash is a strong component, but by itself, it isn’t enough. A resilient, on-chain privacy strategy should be multi-layered, combining multiple tools and protocols to reduce the risk of correlation, surveillance, and failure.
Privacy is never guaranteed by tooling alone. It’s about how the tools are used—strategically, thoughtfully, and with awareness of the threat landscape.