New Gold Protocol Hack Analysis
Price Oracle Manipulation

OraclePrice
22

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

  1. getPrice() function: which basically wraps the price returned by external function getTokenPrice.
    small zoom
    1. getTokenPrice() function, which:
      small zoom
      1. Read directly the current reserves of NGP-USDT pair on Uniswap v2.
        IUniswapV2Pair pair = IUniswapV2Pair(mainPair);
        (uint reserve0, uint reserve1, ) = pair.getReserves();
      2. Used the simple pool ratio of of USDT reserve to NGP reserve to calculate the token's price.
        price = (usdtReserve * 1e18) / tokenReserve;
  2. Whitelisted Addresses
    1. The protocol had a constant DEAD address:
      address constant DEAD = 0x000000000000000000000000000000000000dEaD
    2. The protocol stored a mapping of whitelisted addresses:
      mapping(address => bool) public whitelisted
    3. In constructor the DEAD was listed as whitelisted address along with protocol and mintAddress:
      whitelisted[address(this)] = true;
      whitelisted[address(DEAD)] = true;
      whitelisted[mintAddress] = true;
    4. Whitelisting DEAD address enabled the attacker of bypassing key restrictions and limitations set by contract logic including but not limited to:
      • limit on max buying maxBuyAmountInUsdt which is 10_000.
      • max buy count in 24 hours maxBuyPerDay which is 3 per day.
      • transfer cooldown after buy transferCooldown which is 30 mins.
  3. _update() function:
    `_update` function video
    1. Check if from or to are whitelisted addresses:
      medium zoom
      1. Anyone can transfer from/to `0x...dEaD` as if it were a system contract.
        if (whitelisted[from] || whitelisted[to])
      2. Attacker utilized DEAD address as a bypass gateway to initially route huge volumes of tokens to skip fee deductions, buy/sell caps, and cooldowns.
    2. Buy NGP or Remove Liquidity Logic:
      medium zoom
      1. The spot price feed from getPrice was used in _update function to enforce limitation on the maximum purchase amounts maxBuyAmountInUsdt
        require(((value * getPrice()) / 1e18) <= maxBuyAmountInUsdt, "Exceeds max buy amount");
      2. 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 getPrice function 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.
    3. Sell NGP or Add Liquidity Logic:
      medium zoom

      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%
      1. 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:
        1. 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 lpBurnEnabled is false, then burning is disabled.
          • If lpBurnEnabled is 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.
        2. 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 from to the DEAD address to be burned
            isLpStopBurn() == false
          • If burning has been instead of burning, the same fee is taken from the seller address from and rerouted to the marketAddress
            isLpStopBurn() == true
          • Burning mechanism is designed to either deflationary (burn) tokens or treasury-build (reroute).
        3. 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 from and sent to the protocol’s marketAddress.
          • This means the marketAddress always receives at least marketFee, and sometimes also the burnAmount if burning is disabled.
        4. 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 treasuryAmount and rewardAmount that the protocol mistakenly deducted from the pool reserves directly instead of deducting it from the seller address from. The protocol checks if pool has enough balance to cover sum of treasuryAmount and rewardAmount and if it does:
          • It deducts treasuryAmount from pool's balance directly
            super._update(mainPair, treasuryAddress, treasuryAmount);
          • It deducts rewardAmount from pool's balance directly
            super._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.

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.

Root Cause Summary

  1. 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.
  2. 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.
  3. Whitelisted DEAD Address: Allowed trades routed through the burn address to bypass buy/sell limits, cooldowns, and fee enforcement, removing key protections.
  4. 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.
  5. Misuse of Burn Logic: `isLpStopBurn()` redirected intended burn amounts to the protocol’s market address, undermining token supply deflation and concentrating supply control.
  6. 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.

Strategic Remediation Plan- Recommendations if I Were Leading Response

  1. Immediate Triage: Suspend trading, halt pool interactions, and prevent further depletion.
  2. Whitelist Audit: Remove `DEAD` and other system addresses from privileged lists.
  3. 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.
  4. Fee Rework: Ensure all fees (market, burn, treasury, reward) are charged exclusively from seller transfers.
  5. 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.
  6. Community Communication: Publish a forensic report, outline audited redeploy plans, and define restitution pathways to restore user trust.

Security Takeaways

Incident Report Table

Severity
Critical Direct funds drainage or take control of protocol.
High Severe losses or control issues with some conditions.
Medium Issues that degrade security or amplify bugs.
Low Minor edge cases & small impact.
Informational No direct exploit, but harmful to trust.
Impact
High Directly enabled liquidity drain, major financial loss.
Medium Amplified exploit or weakened tokenomics.
Low Limited effect, cosmetic, or edge-case outcome.
Likelihood
High Trivial to exploit or already weaponized in attack.
Medium Requires conditions or chaining but practical.
Low Edge cases, rare alignment, or theoretical.
Status
Exploited Confirmed used in the $2M NGP hack.
Contributed Amplified the overall exploit.
Design Risk Introduces structural weakness.
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