Introduction to New Gold Protocol
New Gold Protocol is a decentralized finance protocol built on Binance Chain, launched on September 18, 2025, with the stated goal of becoming a "next-generation DeFi 3.0" platform. It aimed to create an inclusive, transparent, and automated staking environment using smart contracts, promoting its native token as deflationary through token burns and promising real-yield distributions instead of speculative incentives. The protocol was designed to achieve transparency, fairness, and sustainability through AI optimization, setting a new benchmark for staking protocols. However, the protocol was exploited just hours after its launch, resulting in the theft of approximately $2 million in assets from its liquidity pool.
Decoding Contract Logic Flaws
The attack exploited critical compounded vulnerabilities in NGP's core smart contract logic primarily because of price oracle manipulation.
What is a Price Oracle Manipulation?
Price Oracle Manipulation is a critical vulnerability in smart contracts that rely on oracles to fetch price and provide real-world data to smart contracts. However, attackers can exploit oracles by manipulating the data they supply, leading to devastating consequences such as unauthorized withdrawals, excessive leverage, or even draining liquidity pools.
Smart Contract vulnerabilities
-
getPrice() function:
which basically wraps the price returned by external function
getTokenPrice.
-
getTokenPrice() function, which:
-
Read directly the current reserves of NGP-USDT pair on Uniswap v2.
IUniswapV2Pair pair = IUniswapV2Pair(mainPair); (uint reserve0, uint reserve1, ) = pair.getReserves(); -
Used the simple pool ratio of of USDT reserve to NGP reserve to calculate the token's price.
price = (usdtReserve * 1e18) / tokenReserve;
-
Read directly the current reserves of NGP-USDT pair on Uniswap v2.
-
getTokenPrice() function, which:
-
Whitelisted Addresses
-
The protocol had a constant
DEADaddress:address constant DEAD = 0x000000000000000000000000000000000000dEaD -
The protocol stored a mapping of
whitelistedaddresses:mapping(address => bool) public whitelisted -
In constructor the
DEADwas listed aswhitelistedaddress along with protocol and mintAddress:whitelisted[address(this)] = true; whitelisted[address(DEAD)] = true; whitelisted[mintAddress] = true; -
Whitelisting
DEADaddress enabled the attacker of bypassing key restrictions and limitations set by contract logic including but not limited to:- limit on max buying
maxBuyAmountInUsdtwhich is 10_000. - max buy count in 24 hours
maxBuyPerDaywhich is 3 per day. - transfer cooldown after buy
transferCooldownwhich is 30 mins.
- limit on max buying
-
The protocol had a constant
-
_update() function:
`_update` function video -
Check if
fromortoare whitelisted addresses:
-
Anyone can transfer from/to `0x...dEaD` as if it were a system contract.
if (whitelisted[from] || whitelisted[to]) -
Attacker utilized
DEADaddress as a bypass gateway to initially route huge volumes of tokens to skip fee deductions, buy/sell caps, and cooldowns.
-
Anyone can transfer from/to `0x...dEaD` as if it were a system contract.
-
Buy NGP or Remove Liquidity Logic:
-
The spot price feed from
getPricewas used in_updatefunction to enforce limitation on the maximum purchase amountsmaxBuyAmountInUsdtrequire(((value * getPrice()) / 1e18) <= maxBuyAmountInUsdt, "Exceeds max buy amount"); -
The price from a single DEX can easily and dramatically manipulate the pool's reserve within a single atomic transaction using a flash loan
to inflate or deflate a token price causing
getPricefunction to report misleading low or high prices which can allow the attacker to bypass the purchase limits that were supposedly to be enforced by contract logic.
-
The spot price feed from
-
Sell NGP or Add Liquidity Logic:
Selling NGP triggered the contract logic to deduct set of fees as follows:
- Market Fee Rate: 3%
- Burn Fee Rate: 2%
- Treasury Fee Rate: 10%
- Reward Fee Rate: 60%
-
Instead of deducting the tokens from seller's balance and transferring the remainder, the protocol
directly reduced tokens from the liquidity pool, followed by executing
sync()function then transfer seller's tokens as detailed below:-
Liquidity Pool Burning Mechanism isLpStopBurn():
This function is a switch that decides whether tokens should still be burned to the DEAD address or whether burning should stop.
-
If
lpBurnEnabledis false, then burning is disabled. -
If
lpBurnEnabledis true, then it calculates how many tokens are left in circulation:surplusAmount = totalSupply - burnedSupply; if the remaining supply is below 10 million tokens, it returns true and stop burning, otherwise it returns false and keep burning.
-
If
-
In
_update()function when someone sells, it calculates the burn fee:burnAmount = (value * burnFeeRate) / RATIO_PRECISION-
If burning is still allowed tokens are taken from seller address
fromto theDEADaddress to be burnedisLpStopBurn() == false -
If burning has been instead of burning, the same fee is taken from the seller address
fromand rerouted to themarketAddressisLpStopBurn() == true - Burning mechanism is designed to either deflationary (burn) tokens or treasury-build (reroute).
-
If burning is still allowed tokens are taken from seller address
-
Market Fee:
marketFee = (value * marketFeeRate) / RATIO_PRECISION super._update(from, marketAddress, marketFee)-
Separately from the burn, the market fee is always taken from seller address
fromand sent to the protocol’smarketAddress. -
This means the
marketAddressalways receives at leastmarketFee, and sometimes also theburnAmountif burning is disabled.
-
Separately from the burn, the market fee is always taken from seller address
-
Treasury and Reward Fees:
burnPoolAmount = treasuryAmount + rewardAmount;-
I personally find this naming confusing and misleading, but upon code investigation you can figure out why it was given that name.
it's the sum of
treasuryAmountandrewardAmountthat the protocol mistakenly deducted from the pool reserves directly instead of deducting it from the seller addressfrom. The protocol checks if pool has enough balance to cover sum oftreasuryAmountandrewardAmountand if it does: -
It deducts
treasuryAmountfrom pool's balance directlysuper._update(mainPair, treasuryAddress, treasuryAmount); -
It deducts
rewardAmountfrom pool's balance directlysuper._update(mainPair, rewardPoolAddress, rewardAmount); - And last, it synchronize the pool state with current changes after deduction! This leads to liquidity to financial losses for liquidity providers and price manipulation due to altered reserves and imbalanced.
-
I personally find this naming confusing and misleading, but upon code investigation you can figure out why it was given that name.
it's the sum of
-
Liquidity Pool Burning Mechanism isLpStopBurn():
This function is a switch that decides whether tokens should still be burned to the DEAD address or whether burning should stop.
-
Check if
Hack Analysis
Attacker combined all above vulnerabilities in a single atomic transaction of manipulating the price via flash loan, bypassing buy limits through the whitelist, and exploiting premature fee and sync logic to sell at an inflated price.
-
Initially attacker swapped funds on PancakeSwap for NGP using several EOAs.
-
Then took a BTCB flash loan from Moolah protocol to use it as a collateral on Venus protocol to borrow vUSDT.
-
Then drawing liquidity from various liquidity pools by several flash loans of BSC-USD from PancakeSwap.
-
Then attacker swapped BSC-USD for NGP in the PancakeSwap pool while setting the recipient address to the whitelisted `DEAD`
address to avoid all NGP restrictions and manipulated the NGP-USDT `getPrice` function to buy the NGP token at artificially low price.
-
Next, attacker utilized the transaction fee being deducted from DEX not from seller vulnerability to inflate the token price by
executing series of swaps using NGP balance to deplete BSC-USD pool entirely after repaying all borrowed tokens while gaining net profit of $2M.
-
Attacker swapped stolen BSC-USD for ETH on KyberSwap.
-
After Successfully acquiring ETH on BNB chain, attacker bridged entire ETH balance to Ethereum chain using Across protocol.
-
Attacker's final step to conceal his crime, he used Tornado Cash to make tracing stolen funds more difficult.
Root Cause Summary
- Flash Loan Oracle Manipulation: Relied on instantaneous spot reserves from a single DEX (NGP-USDT pair) as the sole oracle source, making it trivial to distort price via flash loans.
- Simplistic Price Calculation: Used a direct reserve ratio for pricing, which amplified the effect of manipulated reserves and let the attacker buy tokens at artificially low values.
- Whitelisted DEAD Address: Allowed trades routed through the burn address to bypass buy/sell limits, cooldowns, and fee enforcement, removing key protections.
- Fee Deduction from LP Reserves: Treasury and reward fees were extracted directly from liquidity pool reserves instead of seller balances, breaking AMM invariants and depleting liquidity.
- Misuse of Burn Logic: `isLpStopBurn()` redirected intended burn amounts to the protocol’s market address, undermining token supply deflation and concentrating supply control.
- Abuse of sync(): Forced synchronization after reserve manipulation locked in distorted pool balances as legitimate prices, compounding the exploit’s profitability.
Post-Hack Mitigation
Following the exploit, the New Gold Protocol team acknowledged the incident publicly on September 20, 2025, stating their intent to continue the project and relaunch. However, no concrete remediation steps were provided: no contract upgrades, audits, or restitution plans were announced. Communication was limited to a few posts on X about tracking the attacker’s funds and “resuming activities soon,” leaving users without clear guidance and liquidity severely impacted.
If any organization is willing to track down the hackers, please do so
— New Gold Protocol (@newgoldprotocol) September 20, 2025
Crypto scene is still new and rules are still being stabilized.
Again we emphasize: we will be back.
Strategic Remediation Plan- Recommendations if I Were Leading Response
- Immediate Triage: Suspend trading, halt pool interactions, and prevent further depletion.
- Whitelist Audit: Remove `DEAD` and other system addresses from privileged lists.
- Oracle Hardening: Integrate TWAP (Time-Weighted Average Price) instead of relying on instantaneous pool reserves, and enforce price guards to block extreme deviations. External feeds (e.g., Chainlink) can complement but should not replace robust in-protocol safeguards.
- Fee Rework: Ensure all fees (market, burn, treasury, reward) are charged exclusively from seller transfers.
- Testing & Simulation: Run adversarial stress tests on forked mainnet environments with flash-loan scenarios, leveragingFoundry fuzzing to surface edge cases and logic breaks before redeployment.
- Community Communication: Publish a forensic report, outline audited redeploy plans, and define restitution pathways to restore user trust.
Security Takeaways
- 🧩 Flash loans + raw AMM reserves = guaranteed oracle manipulation.
- 🧩 Never whitelist “dead” or sink addresses.
- 🧩 Preserve AMM invariants: pool reserves must only move via trades, not protocol logic.
- 🧩 Every fee mechanism must be modeled under adversarial scenarios.
- 🧩 Post-exploit recovery is as much about user trust as it is about code fixes.
Incident Report Table
| Severity | Likelihood | Status | Impact | Vulnerability | Description |
|---|---|---|---|---|---|
| Critical | High | Exploited | High | Flash Loan Oracle Manipulation pair.getReserves() |
Relied on a single DEX pool’s spot reserves, allowing attacker to distort NGP-USDT price via flash loans and sell at inflated valuations. |
| Critical | High | Exploited | High | Fee Deduction from LP Reserves Directly Treasury Fees & Reward Fees |
Treasury/reward fees deducted from liquidity pool reserves instead of seller balances, breaking AMM invariant and directly draining pool. |
| High | High | Exploited | High | Whitelisted DEAD Address Whitelisted `from` & `to` |
Enabled bypass of buy caps, cooldowns, and fee checks, allowing attacker to execute unrestricted swaps via DEAD address. |
| High | High | Exploited | High | Simplistic Price Calculation L 346 |
Used a raw reserve ratio without TWAP/guards, making price trivial to manipulate during reserve imbalance. |
| Medium | Medium | Contributed | Medium | Burn Logic Misuse isLpStopBurn() |
Redirected intended burns to market wallet, undermining supply deflation and compounding supply centralization during attack. |
| Medium | Medium | Contributed | Medium | Abuse of sync() sync() |
Locked manipulated reserves as valid pool state, inflating false price and amplifying profitability of attacker’s swaps. |
| Info rmational |
Low | Design Risk | Low | Misleading Naming of Tokens Redistributions burnPoolAmount |
Misnamed variable suggests burning, but actually redistributes tokens, confusing devs and auditors. |
Level Up Your Security Skills with Cyfrin Updraft
A hands-on smart contract security education platform designed to help developers, auditors, and protocol teams master adversarial thinking through challenges, tutorials, and real-world exploit case studies.
Start Learning