Press ESC to close

Fake GIWA Chain Exploit: 766 ETH Stolen via Rogue L2 Bridge

An analysis of the sophisticated fake GIWA mainnet scam that drained 766 ETH from users on September 27, 2026, and compromised the DYORSWAP decentralized exchange due to malicious RPC integration.

A Masterclass in Deception: Faking a Blockchain

I was scrolling through my security monitoring feed and nearly dropped my coffee. Seven hundred and sixty-six ETH. Just gone into the ether (no pun intended). If it had been a standard front-end phishing attack using a compromised library or a flash-loan contract exploit, I wouldn't have batted an eye—I've seen it all. But this scheme was way more clever. The bad actors spun up a rogue GIWA mainnet, hooked it up to someone else's DEX, and cleaned out users to the tune of a couple million bucks.

Let's break down this incident step-by-step, because architecturally speaking, there's some fascinating engineering here. As a security specialist and active CTO, I almost have to tip my hat to the audacity of the execution—though I definitely don't envy the team at DYORSWAP.

Wait, how can anyone even "fake" a Layer 2 blockchain? It sounds wild to anyone outside the space, but in the EVM world, a network isn't magic; it's just a set of conventions and RPC endpoints.

The attackers grabbed an open-source stack (likely forking something like the OP Stack) and spun up a node. But standing up a server isn't enough; you have to trick wallets and apps into believing it's the official product of Upbit, the South Korean exchange whose GIWA network hadn't even officially launched its mainnet yet.

They hardcoded the official Chain ID—number 9134, which the GIWA team had registered ahead of time for their upcoming blockchain—directly into the node configuration. And right there lies the core vulnerability of the entire ecosystem: wallets like MetaMask validate networks based on config strings and IDs rather than cryptographic roots of trust tied to the actual creators.

And that brings us to where DYORSWAP dropped the ball. They added this fake RPC straight into their infrastructure, eager to be first in line to farm the hype of the new network.

You know, back when I used to audit smart contracts on the side, we always figured: fine, the front-end can get spoofed, the RPC can get swapped out, but the bridge smart contract is sacred—that code lives right there on Ethereum! And that's where the most elegant trap of this attack was sprung.

Why Did Users Suspect Nothing?

Users didn't suspect a thing because the bridge looked just like a native interface for moving funds from Ethereum to the GIWA L2 network. People signed transactions in MetaMask, sending their hard-earned ETH straight to a deposit smart contract on the mainnet.

Technically, the attackers coded this contract to mimic a standard deposit locator. As soon as the transaction cleared validation on mainnet, the scammers had full control of the funds. In return, the user received worthless, unbacked shitcoins credited to their balance on the fake L2. The numbers on the screen ticked up, creating the illusion of a successful bridge, while the real ETH had already flown away to the organizers' addresses, washing out through mixers. In the end, 1,335 unique addresses got burned, trapping roughly 767.7 ETH. They managed to cash out around 766.3 ETH cleanly, optimizing gas costs to a bare minimum.

The DYORSWAP team stepped up massively, covering over 200 ETH out of pocket for user compensation. Gotta respect that kind of commitment to reputation, even if they're going to need to patch that external RPC validation hole ASAP.

Now, let's look at the practical side. How do you avoid becoming an involuntary sponsor for the next wave of scammers if you love being an early adopter of new blockchains? I put together a quick Python check script to verify RPC nodes before you even think about interacting with them via your wallet.

#!/usr/bin/env python3
import requests
def rpc_call(rpc_url, method, params=None):
    if params is None:
        params = []
    payload = {
        "jsonrpc": "2.0",
        "method": method,
        "params": params,
        "id": 1
    }
    response = requests.post(rpc_url, json=payload, timeout=10)
    response.raise_for_status()
    data = response.json()
    if "error" in data:
        raise RuntimeError(f"{method}: {data['error']}")
    return data.get("result")
def verify_evm_node(rpc_url, expected_chain_id):
    try:
        chain_id_hex = rpc_call(rpc_url, "eth_chainId")
        chain_id = int(chain_id_hex, 16)
        net_version = rpc_call(rpc_url, "net_version")
        client_version = rpc_call(rpc_url, "web3_clientVersion")
        block_number_hex = rpc_call(rpc_url, "eth_blockNumber")
        block_number = int(block_number_hex, 16)
        latest_block = rpc_call(
            rpc_url,
            "eth_getBlockByNumber",
            ["latest", False]
        )
        print("=" * 60)
        print(f"RPC URL         : {rpc_url}")
        print(f"Chain ID        : {chain_id}")
        print(f"Expected ChainID : {expected_chain_id}")
        print(f"Net Version     : {net_version}")
        print(f"Client Version   : {client_version}")
        print(f"Block Number     : {block_number}")
        if latest_block:
            print(f"Latest Block Hash: {latest_block.get('hash')}")
            print(f"Latest Block Num : {int(latest_block['number'], 16)}")
            print(f"Parent Hash      : {latest_block.get('parentHash')}")
            print(f"Timestamp        : {int(latest_block['timestamp'], 16)}")
        print("=" * 60)
        checks = []
        checks.append(chain_id == expected_chain_id)
        try:
            checks.append(int(net_version) == expected_chain_id)
        except Exception:
            checks.append(False)
        checks.append(block_number > 0)
        checks.append(
            latest_block is not None
            and latest_block.get("hash")
            and latest_block.get("parentHash")
            and latest_block.get("number")
        )
        if all(checks):
            print("VERIFICATION PASSED")
            return True
        print("VERIFICATION FAILED")
        return False
    except Exception as e:
        print(f"ERROR: {e}")
        return False
if __name__ == "__main__":
    verify_evm_node(
        "https://your-rpc-endpoint",
        9134
    )

Remember the golden rule: never trust network lists dropped by sketchy Twitter accounts or unverified DEXs until the actual project publishes exact endpoints through their official, verified channels (not social media hype posts, but documentation or an official website backed by valid SSL certificates). Upbit explicitly stated that their mainnet hasn't even launched yet, meaning any current RPCs out in the wild are pure guesswork and total scams.

Summarize this blog post with:

FAQ

Scammers deployed a rogue EVM-compatible Layer 2 node using the official unreleased GIWA Chain ID 9134, integrated a fraudulent cross-chain deposit contract, and tricked 1,335 user wallets into transferring real ETH in exchange for worthless native balances.

The decentralized exchange automatically verified network legitimacy based on the matching Chain ID 9134, failing to perform cryptographic root validation or cross-referencing official Upbit announcements before connecting their infrastructure.

Developers and users must cross-verify RPC responses using native methods like net_version, inspect block header continuity (eth_getBlockByNumber), and rely solely on officially signed documentation channels rather than preliminary network parameters.
Oleg Filatov

As the Chief Technology Officer at EXMON Exchange, I focus on building secure, scalable crypto infrastructure and developing systems that protect user assets and privacy.

With over 15 years in cybersecurity, blockchain, and DevOps, I specialize in smart contract analysis, threat modeling, and secure system architecture.

At EXMON Academy, I share practical insights from real-world...

...

Leave a comment

Your email address will not be published. Required fields are marked *