Press enter or click to view image in full size
Bug bounty hunting in Web3 isn’t just about analyzing smart contracts for reentrancy or logic flaws. Sometimes, the biggest vulnerabilities hide in the off-chain infrastructure.
In this write-up, I’ll share my experience of discovering a highly sensitive infrastructure misconfiguration in a prominent DeFi protocol (let’s call it TargetX). What started as a simple API scan escalated into uncovering a private simulation environment containing over $25 Million in manipulated assets, and how I had to prove my case when the triage team initially rejected it.
While analyzing TargetX’s web applications, I noticed they were making requests to a custom RPC endpoint: https://rpc.target.com.
Out of curiosity, I sent a basic POST request to the root endpoint. As expected, it returned a 403 Forbidden / Gateway Error. The developers had clearly put a firewall or reverse proxy in front of it.
However, in the Web3 world, RPC endpoints often route traffic based on Chain IDs. I decided to fuzz the URL paths by appending standard EVM Chain IDs.
The Bypass:
Sending a request to https://rpc.target.com/1 (appending /1 for Ethereum Mainnet) bypassed the 403 restriction entirely! The endpoint responded with a valid 200 OK JSON-RPC response.
Now that I had unauthenticated access to their internal node, I wanted to see what state this node was tracking. I targeted one of TargetX’s core vault contracts (0xVaultAddress...) and queried its balance.
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0xVaultAddress...", "latest"],"id":1}' \
https://rpc.target.com/1The Result: 0x22d68445673d07axxxx
Converting this hex to decimal revealed a staggering balance of ~10,282 ETH (worth around $25+ Million at the time).
But here was the catch: I cross-referenced this exact contract address on the real Ethereum Mainnet via Etherscan. The real balance was only ~2,599 ETH (around $7.7 Million).
Where did the extra $22 Million come from? ### Phase 3: Fingerprinting the Infrastructure
The balance mismatch was a massive red flag. Real public nodes mirror the exact state of the blockchain. This node was hallucinating funds. I needed to identify what backend technology TargetX was actually running.
I used the web3_clientVersion RPC method to fingerprint the node:
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":1}' \
https://rpc.target.com/1The Response: {"jsonrpc":"2.0","id":1,"result":"Tenderly/1.0"}
Bingo! The backend wasn’t a standard Geth or Erigon node. It was a Tenderly Virtual Fork. TargetX had accidentally exposed their private, paid simulation and testing environment to the public internet without any API key authentication.
I quickly wrote up a detailed report explaining the exposed Tenderly fork, the information disclosure of internal EIP-1967 proxy slots, and the potential for infrastructure quota exhaustion.
Join Medium for free to get updates from this writer.
A few hours later, I received a response from the triage team:
“Closed as Informative. This is just an erpc proxy routing to public nodes. The data you are fetching is public blockchain data. There is no security impact.”
They completely missed the point. They assumed my results were just public Mainnet data. I needed a “Killer Proof” to demonstrate that this was a manipulatable simulation environment, not a read-only public proxy.
Public RPC proxies (like Infura, Alchemy, or generic public nodes) strictly prohibit unauthorized users from modifying the blockchain state. However, Tenderly simulation forks allow a powerful feature called State Overrides via the eth_call method.
I decided to perform a simulated hijacking of their Proxy Contract. I crafted a request to query the proxy’s implementation address, but I injected a stateDiff parameter to artificially overwrite the EIP-1967 Logic Slot (0x360894...) with a dummy address (0x1111...).
curl -X POST -H "Content-Type: application/json" \
--data '{
"jsonrpc":"2.0",
"method":"eth_call",
"params":[
{"to":"0xVaultAddress...", "data":"0xd781aaec"},
"latest",
{
"0xVaultAddress...": {
"stateDiff": {
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3caxxxxxxxxxx": "0x0000000000000000000000001111111111111111111111111111111111111111"
}
}
}
],
"id":1
}' \
https://rpc.target.com/1The Result: {"jsonrpc":"2.0","id":1,"result":"0x"}
Checkmate. Because I overwrote the logic address with a non-existent contract (0x1111...), the call returned 0x. If this had been a true public proxy as the triage team claimed, it would have rejected the stateDiff parameter entirely or returned the actual implementation address. The RPC processed my state override, definitively proving it was an active simulation environment.
I replied to the triage team with my final evidence:
web3_clientVersion proving the Tenderly backend.2. The $22M asset mismatch proving an artificial state.
3. The successful execution of a State Override proving simulation capabilities.
I politely explained that exposing a private development fork allows attackers to reverse-engineer unreleased protocol logic, perform dark-forest simulations on upcoming deployments, and exhaust their paid infrastructure quotas.
Shortly after, the team acknowledged the technical proof, reopened the ticket, and validated the vulnerability.
web3_clientVersion to know exactly what you are talking to.Happy Hunting! 🐺
#Web3Security #BugBounty #Infosec #EthicalHacking #BlockchainSecurity #Ethereum #EVM #DeFiSecurity #SmartContracts #Tenderly #RPC
Press enter or click to view image in full size