Durante a semana passada (2026/03/09 - 2026/03/15), a BlockSec detectou e analisou oito incidentes de ataque, com perdas totais estimadas em ~$1,66M. A tabela abaixo resume esses incidentes, e análises detalhadas de cada caso são fornecidas nas subseções a seguir.
| Data | Incidente | Tipo | Perda Estimada |
|---|---|---|---|
| 2026/03/09 | Incidente EtherFreakers | Lógica de negócio falha | ~$25K |
| 2026/03/10 | Incidente Alkemi | Lógica de negócio falha | ~$89K |
| 2026/03/10 | Incidente MT | Lógica de negócio falha | ~$242K |
| 2026/03/11 | Incidente de Liquidação AAVE | Configuração incorreta | ~$1,01M |
| 2026/03/11 | Incidente Planet Finance | Lógica de negócio falha | ~$10K |
| 2026/03/12 | Incidente AM | Lógica de negócio falha | ~$131K |
| 2026/03/12 | Incidente DBXen | Lógica de negócio falha | ~$149K |
| 2026/03/15 | Incidente Goose Finance | Lógica de negócio falha | ~$8K |
Incidente EtherFreakers
Resumo
Em 9 de março de 2026, o EtherFreakers, um jogo NFT na Ethereum, foi explorado devido a uma dupla contagem incorreta, resultando em uma perda de ~$25K. Cada NFT no jogo possui um saldo de ETH sacável (chamado de "energia"). Como mecânica do jogo, os jogadores podem usar attack() para fazer um NFT capturar outro e reivindicar a energia do alvo. No entanto, o contrato paga o saldo do alvo, mas transfere o NFT antes de liquidar sua contabilidade. Um hook de transferência então lê dados desatualizados anteriores ao pagamento e os alimenta parcialmente de volta em um pool global de dividendos, inflando o pool sem novo ETH como lastro. O explorador repetiu essa mecânica de captura para inflar o índice global e então drenou o saldo inflado de um lote de NFTs.
Contexto
EtherFreakers é um jogo NFT on-chain onde cada NFT (chamado de "Freaker") possui um saldo de ETH sacável chamado energy. O sistema funciona como um pool de dividendos: quando certas ações ocorrem, uma fração de ETH é distribuída proporcionalmente a todos os Freakers. O ETH reclamável de cada Freaker é rastreado por um acumulador global freakerIndex combinado com um peso de participação por token fortune.
Concretamente, a fórmula contábil é: energyOf = basic + (freakerIndex - index) * fortune. O freakerIndex aumenta quando _dissipateEnergyIntoPool(amount) é executado, distribuindo 80% do amount para todos os Freakers e 20% para os criadores. Depósitos diretos via charge() aumentam apenas o basic sem afetar o freakerIndex. Portanto, aumentos no freakerIndex devem sempre ser respaldados por Ether real entrando no sistema. Se o freakerIndex crescer sem o correspondente influxo de ETH, os Freakers podem resgatar mais Ether do que o contrato realmente possui.
Análise de Vulnerabilidade
A causa raiz é uma ordem de execução incorreta no contrato EtherFreak (0x3A27...c0f33). Quando uma captura é bem-sucedida, a função attack() executa estes passos em ordem:
- Linha 237: Paga
targetCharge(a energia total do NFT alvo) ao defensor como uma transferência direta de ETH. A energia é agora gasta. - Linha 240: Chama
_transfer(defender, capturer, targetId)para mover o NFT. Internamente,_transfer()invoca o hook ERC-721_beforeTokenTransfer(), que chama_dissipateEnergyIntoPool()com 0,1% deenergyOf(targetId). Esta é a primeira chamada a_dissipateEnergyIntoPool(), e ela lê um valor desatualizado porque o passo 5 ainda não ocorreu. - Linha 241: Chama
_dissipateEnergyIntoPool(sourceSpent)explicitamente. Esta é a segunda chamada, que faz parte da lógica normal do jogo. - Linhas 244-251: Atualiza
energyBalancestanto parasourceIdquanto paratargetId.
O bug está no passo 2: como energyBalances[targetId] ainda não foi atualizado, o hook ainda vê o saldo anterior ao pagamento e alimenta parte da energia já gasta no pool de dividendos. O pagamento direto em ETH no passo 1 e a entrada no pool no passo 2 ambos consomem a mesma energia, inflando freakerIndex sem novo lastro em ETH.


freakerIndex cresce sempre que _dissipateEnergyIntoPool() é chamado:

Análise do Ataque
A análise a seguir é baseada na transação 0x89e24d...9abd2942.
-
Passo 1: Emprestar
1.700WETHvia flash loan. -
Passo 2: Criar dois novos Freakers, token
590e token591, sob endereços controlados pelo explorador. -
Passo 3: Chamar repetidamente a função
attack(590, 591)do jogo e manter as execuções no ramo de captura bem-sucedida. -
Passo 4: Após cada sucesso, transferir o token
591de volta ao auxiliar para que o mesmo par possa ser reutilizado. -
Passo 5: Cada iteração bem-sucedida infla o
freakerIndexalém do Ether realmente conservado pelo sistema. -
Passo 6: Uma vez que o índice é suficientemente alto, descarregar um lote de Freakers previamente controlados. Os IDs de token
496a520são cada um descarregado por0,278052246002402082Ether. -
Passo 7: Converter o Ether drenado em
WETH, pagar o flash loan de1.700WETH, e manter cerca de7,498WETHcomo lucro.
Conclusão
A causa raiz está no fluxo de captura bem-sucedida de attack(): o EtherFreakers paga targetCharge antes que o estado de energia do token alvo seja liquidado. _transfer() então aciona _beforeTokenTransfer(), que lê o energyOf(targetId) desatualizado anterior ao pagamento e dissipa parte dele no pool. Isso aumenta o freakerIndex sem novo lastro em Ether, fazendo com que a mesma energia do alvo seja contabilizada tanto como pagamento quanto como entrada no pool. Este é um bug de inflação de lógica de negócio, não um bug de reentrância.
Para reduzir riscos semelhantes no futuro:
-
Evite recomputar valores econômicos a partir de estado mutável dentro de hooks de transferência enquanto a mesma transação ainda está sendo liquidada.
-
Se o hook de transferência lê uma variável de estado, garanta que a ordem de execução não afete o resultado (por exemplo, liquide o estado antes que o hook seja executado, não depois).
Incidente Alkemi
Resumo
Em 10 de março de 2026, o protocolo Alkemi na Ethereum foi explorado, resultando em uma perda de ~$89K. A causa raiz é um erro contábil e uma lógica de negócio falha. A lógica de liquidação falha permite que qualquer pessoa liquide sua própria posição dentro da mesma transação e lucre com isso. Além disso, um erro contábil faz com que a dedução da própria garantia do atacante durante a liquidação seja sobrescrita, permitindo que o atacante obtenha recompensas de liquidação sem arcar com o custo pretendido.
Contexto
Alkemi é um protocolo de empréstimo. Quando a posição de um tomador de empréstimo fica subcapitalizada, qualquer pessoa pode chamar liquidateBorrow() para pagar parte da dívida e confiscar a garantia com desconto. Para evitar liquidações excessivas, o protocolo limita o valor máximo reembolsável por transação ao mínimo de três valores:
- O saldo de empréstimo atual do tomador (
currentBorrowBalance_TargetUnderwaterAsset). - O reembolso máximo que a garantia do tomador pode cobrir após aplicar o desconto de liquidação (
calculateDiscountedBorrowDenominatedCollateral()). - O valor de reembolso necessário para trazer a conta de volta ao limite de liquidação (
calculateDiscountedRepayToEvenAmount()), verificado apenas quando o mercadoisSupported.


Análise de Vulnerabilidade
A causa raiz é a lógica de negócio falha e um erro contábil no protocolo Alkemi (0x4822...a888). Como currentBorrowBalance_TargetUnderwaterAsset é necessariamente maior que 0 enquanto o tomador tiver uma dívida pendente, e o valor retornado por calculateDiscountedBorrowDenominatedCollateral() também é necessariamente maior que 0 enquanto o tomador tiver garantia, o protocolo AlkemiEarnPublic efetivamente depende de calculateDiscountedRepayToEvenAmount() para determinar se um dado empréstimo pode ser liquidado. Nessa função, o valor da dívida que precisa ser liquidada deve ser calculado com base em uma variável chamada accountShortfall_TargetUser.
No entanto, na implementação real, a função utiliza uma variável global closeFactorMantissa para calcular um limite superior sobre o valor da dívida que pode ser reembolsado, e retorna esse valor. Como resultado, um atacante consegue tomar emprestado e imediatamente liquidar sua própria posição dentro da mesma transação.
Além disso, na função liquidateBorrow(), quando o liquidante e o tomador são o mesmo endereço, as variáveis supplyBalance_TargetCollateralAsset e supplyBalance_LiquidatorCollateralAsset apontam para o mesmo slot de armazenamento. A função então calcula um "saldo reduzido" e um "saldo recompensado" separadamente com base no mesmo saldo inicial, e subsequentemente os grava de volta no mesmo slot de armazenamento em sequência. Como o saldo reduzido é gravado primeiro e o saldo recompensado é gravado depois, o efeito de redução é sobrescrito e perdido, deixando apenas o resultado recompensado. Isso permite que o atacante amplifique ainda mais seu lucro.
Análise do Ataque
A análise a seguir é baseada na transação 0xa170...6d9d.
-
Passo 1: O atacante obteve um flash loan de
51e18WETHda Balancer. -
Passo 2: O atacante converteu
51e18WETHemETHe forneceu ao protocolo Alkemi. -
Passo 3: O atacante tomou emprestado
39,5e18ETHda Alkemi. -
Passo 4: O atacante liquidou sua própria posição usando
39,5395e18ETH. -
Passo 5: O atacante retirou
93,5e18ETHda Alkemi. -
Passo 6: O atacante reembolsou o flash loan e obteve um lucro de
43,4e18ETH.

Conclusão
A causa raiz é que a lógica de liquidação falha permite que o atacante tome emprestado e então liquide sua própria posição dentro da mesma transação para obter lucro, enquanto a lógica contábil incorreta amplifica ainda mais os ganhos do atacante.
Para reduzir riscos semelhantes no futuro:
- Para atualizações de saldo do tomador e do liquidante, o protocolo deve operar diretamente nas variáveis de armazenamento em vez de copiar os saldos para variáveis de memória temporárias para cálculo e gravação de volta separados.
Incidente MT
Resumo
Em 10 de março de 2026, o MT Token, um token deflacionário na BNB Chain, foi explorado, resultando em uma perda de ~$242K. A causa raiz é uma lógica de restrição de negociação falha combinada com tratamento inconsistente de condições especiais de transferência. Durante a fase de deflação, o contrato restringe operações de compra quando a reserva do pool excede um limite fixo. No entanto, o contrato trata transferências de valores exatos (por exemplo, 2e17 MT) como ações de vínculo de referência, permitindo que o atacante contorne a restrição de compra e adquira tokens iniciais. Além disso, a lógica de restrição depende de detecção de caminho incompleta (isBuy) e não cobre rotas de swap indiretas como Pair para Router, enquanto verificações de lista de permissões encurtam validações críticas. O atacante acumulou tokens MT sem acionar restrições ou taxas, manipulou pendingBurnAmount via operações controladas de liquidez e negociações, e forçou o pool a um estado anormal onde o preço do token foi artificialmente inflado.
Contexto
MT Token é um token deflacionário na BNB Chain com restrições de negociação integradas. Durante a fase de deflação, o contrato bloqueia operações de compra quando a reserva de MT no pool excede 21.000e18. Uma vez que a reserva caia abaixo desse limite, a fase de deflação termina e as compras são reativadas. MT Token também inclui um mecanismo de referência: uma transferência de exatamente 2e17 MT ou 1e17 MT é tratada como uma ação de vínculo de referência em vez de uma negociação normal.
Análise de Vulnerabilidade
A causa raiz foi um design de restrição de compra falho no contrato MT (0x037E...b449). Em condições normais, os atacantes deveriam ser incapazes de adquirir MT como capital inicial durante a fase restrita. No entanto, o contrato trata uma transferência de exatamente 2e17 MT como uma ação de vínculo de referência em vez de uma compra, o que permite que um atacante adquira 2e17 MT contornando a restrição de compra.

Além disso, a restrição de negociação depende do ramo isBuy para bloquear compras, mas não cobre o caminho "Pair para Router". Como tanto o Router quanto o Pair são endereços da lista de permissões, tais transferências encurtam na verificação da lista de permissões e nunca alcançam a lógica de restrição de compra, permitindo que um atacante adquira MT roteando compras para o Router e subsequentemente extraindo tokens de volta para si mesmo removendo liquidez.

Análise do Ataque
A análise a seguir é baseada na transação 0xfb57...fca6.
-
Passo 1: O atacante obteve um flash loan de
~358.681e18WBNB. -
Passo 2: O atacante comprou
2e17MT, contornando assim a restrição de compra. -
Passo 3: O atacante forneceu
4e12WBNBe2e17MTao Pair para adicionar liquidez. Essa transferência contornou a lógica de cobrança de taxas pelo mesmo motivo acima. -
Passo 4: O atacante comprou
~10.000.000e18tokensMTdo Pair para o Router, contornando assim tanto a restrição de compra quanto a lógica de cobrança de taxas. -
Passo 5: O atacante removeu metade de sua posição de liquidez, extraindo todos os tokens
MTmantidos pelo Router no processo, e então vendeu oMTrecuperado porWBNB. Neste passo,pendingBurnAmountfoi manipulado para aproximadamente9.000.000e18.
-
Passo 6: O atacante comprou
~10.000.000e18tokensMTnovamente, reduzindo a reserva deMTdo pool para~6.756.516e18, que era menor quependingBurnAmount.
-
Passo 7: O atacante removeu a metade restante de sua posição de liquidez, retirou os tokens
MTcomprados e então chamoudistributeDailyRewards()para queimarMTdo pool. Como resultado, a reserva deMTfoi reduzida para21.000e18.
-
Passo 8: O atacante trocou todo o
MTde volta por~1.198e18WBNB, reembolsou o flash loan e finalizou o lucro.
Conclusão
Este exploit foi causado por restrições de negociação incorretas, que permitiram ao atacante contornar a proibição de compra adquirindo exatamente BINDING_AMOUNT de tokens MT. Após obter tokens MT, o atacante conseguiu contornar tanto a lógica de cobrança de taxas quanto a restrição de compra adicionando liquidez primeiro, depois comprando MT para o Router, e finalmente removendo liquidez para recuperar os tokens. O atacante então acumulou pendingBurnAmount via operações de venda e executou a queima para empurrar as reservas do pool a um estado anormal, permitindo-lhe vender MT a um preço inflado artificialmente e lucrar.
Para reduzir riscos semelhantes no futuro:
- Imponha separação estrita entre semântica de transferência e lógica de negociação.
Incidente de Liquidação AAVE
Resumo
Em 11 de março de 2026, a AAVE sofreu $21M em liquidações incorretas na Ethereum, resultando em uma perda de ~$1,01M. A causa raiz foi um preço oracle incorreto para wstETH, que fez com que posições originalmente saudáveis se tornassem subcapitalizadas. Como resultado, as posições dos usuários foram liquidadas, levando a perdas financeiras.
Contexto
A AAVE usa adaptadores de oracle para precificar ativos encapsulados como wstETH. O adaptador CAPO (Capped Price Oracle) deriva o preço do wstETH multiplicando o preço base de ETH/USD por uma taxa de conversão (getRatio(), ou seja, quanto ETH vale um wstETH). Para evitar manipulação da taxa, o CAPO aplica um limite de crescimento baseado em snapshot:
maxRatio = snapshotRatio + maxGrowthPerSecond x (currentTime - snapshotTimestamp)
e limita a saída de getRatio() durante a precificação (se currentRatio > maxRatio, usa maxRatio). Esse mecanismo limita efetivamente a deriva máxima ascendente da taxa e o preço resultante.
Análise de Vulnerabilidade
A causa raiz foi uma incompatibilidade tempo-taxa na configuração âncora do oracle CAPO (0xe1D9...61Ef): o timestamp do snapshot e a taxa do snapshot foram configurados, mas a taxa do snapshot foi configurada abaixo da taxa real de wstETH/ETH. Como resultado, o maxRatio calculado pelo adaptador ficou abaixo da taxa ao vivo e limitou getRatio() para baixo, subvalorizando sistematicamente o preço oracle de wstETH/USD. Essa desvalorização da garantia reduziu o fator de saúde das posições usando wstETH como garantia, fazendo com que contas originalmente saudáveis fossem incorretamente classificadas como não saudáveis e liquidadas.


Análise do Ataque
A análise a seguir é baseada na transação 0x9064...8a9c.
-
Passo 1: O liquidante obteve um flash loan de
~6304e18WETHe liquidou o tomador. -
Passo 2: O liquidante reembolsou o flash loan, completando a liquidação.
Conclusão
Essa liquidação foi causada por uma configuração incorreta do preço oracle, que empurrou incorretamente os tomadores que deveriam permanecer saudáveis para um estado não saudável, acionando assim a liquidação de suas posições.
Para reduzir riscos semelhantes no futuro:
-
Garanta que parâmetros críticos sejam verificados quanto à correção antes de cada atualização.
-
Adicione verificações de validação na implementação para rejeitar parâmetros incorretos e impedir que configurações incorretas sejam aplicadas com sucesso.
Incidente Planet Finance
Resumo
Em 11 de março de 2026, o Planet Finance foi explorado na BNB Chain, resultando em uma perda estimada de ~$10K. A causa raiz foi que o protocolo tratou erroneamente aumentos no saldo de empréstimo armazenado de um tomador como juros acumulados, permitindo que um atacante tomasse emprestado e acionasse a liquidação de descontos repetidamente para subestimar sua dívida registrada.
Contexto
Planet Finance é um protocolo de empréstimo que permite que os tomadores paguem com um desconto nos juros. O desconto é escalonado e determinado pela proporção entre o GAMMA apostado pelo usuário e seu valor apostado em outros ativos: quanto maior essa proporção, maior o desconto no reembolso. O cronograma de desconto compreende três níveis, variando de 0% (mínimo) a 50% (máximo).
Análise de Vulnerabilidade
A causa raiz foi que, ao liquidar o desconto de um tomador em changeUserBorrowDiscount(), o protocolo (0x4c9E...F467) tratou erroneamente o aumento no saldo de empréstimo armazenado do tomador como juros recém-acumulados. Como resultado, o desconto destinado a aplicar-se apenas a juros acumulados foi incorretamente aplicado ao principal recém-tomado emprestado, reduzindo indevidamente a dívida registrada do tomador. Um atacante poderia realizar repetidamente o ciclo borrow seguido de changeUserBorrowDiscount para acumular descontos excessivos, fazendo com que o passivo registrado on-chain fosse consistentemente menor do que o valor real emprestado, e eventualmente lucrar com a discrepância.


Análise do Ataque
A análise a seguir é baseada na transação 0x5f45...5ec9.
-
Passo 1: O atacante obteve um flash loan de
200.000e18USDT. -
Passo 2: O atacante usou
5.000e18USDTpara comprarWBNB, e então usou oWBNBadquirido para comprar~8.726.524e18GAMMA. -
Passo 3: O atacante primeiro apostou todo o
GAMMAadquirido no mercado gGAMMA, depois forneceu oUSDTrestante como garantia, o que aumentou seu desconto de reembolso para 5% e habilitou o empréstimo subsequente. -
Passo 4: O atacante chamou repetidamente
borrowe depoisupdateUserDiscountpara reduzir continuamente sua dívida registrada.
-
Passo 5: O atacante finalmente reembolsou a dívida, resgatou a garantia e realizou o lucro.
Conclusão
Este incidente foi causado pela lógica de liquidação de desconto falha do Planet Finance em changeUserBorrowDiscount(), que erroneamente trata o aumento no saldo de empréstimo armazenado de um tomador como juros recém-acumulados e aplica o desconto de juros sobre esse delta. Um atacante pode repetidamente chamar borrow seguido de updateUserDiscount para subestimar sua dívida registrada e, em última análise, pagar menos do que o passivo real para extrair lucro.
Para reduzir riscos semelhantes no futuro:
- Diferencie juros e novos empréstimos no protocolo de empréstimo.
Incidente AM
Resumo
Em 12 de março de 2026, o AM Token, um token deflacionário na BNB Chain, foi explorado com uma perda estimada de ~$131K. O AM Token implementa um mecanismo deflacionário onde cada venda aciona uma queima adicional do pool de liquidez, removendo permanentemente tokens para reduzir o fornecimento total. No entanto, a queima não é executada imediatamente - em vez disso, o valor total da venda é registrado como toBurnAmount e a queima real é adiada para a próxima venda. Esse atraso cria uma janela entre o registro e a execução, durante a qual um atacante pode recomprar AM para reduzir a reserva de AM do pool até toBurnAmount. Quando a próxima venda aciona a queima diferida, toda a reserva de AM é eliminada, elevando o preço a um nível extremo e permitindo que o atacante venda AM com lucro.
Contexto
AM Token é um token deflacionário na BNB Chain. Em cada venda, o contrato registra a quantidade de AM envolvida no swap como toBurnAmount, e queima essa quantidade registrada do pool de liquidez durante a próxima venda. Na prática, as vendas acionam uma queima atrasada que reduz a reserva de AM do pool. Além disso, antes de executar a queima, o protocolo converte o totalTokenFee acumulado em USDT e o distribui de acordo com sua lógica de alocação de taxas.
Análise de Vulnerabilidade
A causa raiz foi que a lógica de venda do token (0x27f9...213f) acumula o valor total de AM trocado como toBurnAmount e só executa a queima na próxima venda, removendo tokens do par AM/USDT e chamando pair.sync() para atualizar as reservas. Esse design permite que um atacante manipule as reservas de AM do pool, distorça o preço on-chain e lucre via arbitragem.


Análise do Ataque
A análise a seguir é baseada na transação 0xd0d1...f859.
-
Passo 1: O atacante obteve um flash loan de
~27.265.119e18USDCe~361.710e18WBNB, e então os converteu em~100.423.811e18USDT. -
Passo 2: O atacante trocou
~5.062e18tokensAMporUSDT, o que manipulou otoBurnAmountregistrado no contrato para~4.303e18.
-
Passo 3: O atacante trocou
USDTpor AM Token, reduzindo a reserva deAMdo pool para~4.303e18.
-
Passo 4: O atacante transferiu
6 weideAMpara o pool, acionando a lógica de queima do caminho de venda. Como resultado, o contrato queimou todo o saldo deAMdo pool, reduzindo a reserva deAMpara 0. Nota: o protocolo primeiro tenta converter as taxas acumuladas emUSDTantes da queima. Esse caminho de conversão de taxas também aciona a lógica de queima do ramo de venda. Após a queima ser executada e a reserva deAMchegar a 0, o swap de taxas falha. Como está envolto em um try/catch, a falha não reverte a transação. Em vez disso, a execução continua e o acumulador de taxas é redefinido para 0.
-
Passo 5: O atacante chamou
pool.sync()e transferiu oUSDTrestante e1 weideAMpara o pool. Como ambos os tokens foram transferidos simultaneamente, o contrato tratou isso como addLiquidity, de modo quetoBurnAmountnão foi acumulado. A reserva deAMfoi atualizada para 7.

-
Passo 6: O atacante trocou os tokens
AMrestantes porUSDT. Durante esse swap, a transferência deAMpara o Pair acionou a lógica de queima do caminho de venda, reduzindo a reserva deAMpara 1. Além disso, comototalFeeAmounthavia sido redefinido para 0 no Passo 4, a conversão de taxas paraUSDTnão foi mais executada, permitindo que o atacante vendesseAMa um preço artificialmente inflado.
-
Passo 7: O atacante reembolsou o flash loan e realizou o lucro restante.
Conclusão
Este incidente foi causado pelo mecanismo de queima falho do AM Token, que acumula o AM envolvido no swap de cada venda como toBurnAmount e então queima essa quantidade do Par AM/USDT na próxima venda enquanto chama pool.sync(). Isso permite que um atacante manipule as reservas de AM do Par para um nível extremo e venda AM a um preço artificialmente inflado para drenar USDT.
Para reduzir riscos semelhantes no futuro:
- Limite o valor máximo de queima por transação e limite a frequência com que a queima pode ser acionada, impedindo que atacantes consumam uma grande parte das reservas de tokens do pool em um curto período de tempo.
Incidente DBXen
Resumo
Em 12 de março de 2026, o DBXen, um protocolo burn-to-earn na Ethereum e BNB Chain, foi explorado com uma perda total de ~$149K. A causa raiz foi uma inconsistência entre _msgSender() e msg.sender. Quando burnBatch() é chamado pelo forwarder, a quantidade de XEN queimado é registrada sob _msgSender() (controlado pelo atacante), mas os registros de ciclo são atualizados em msg.sender (o forwarder). Essa divisão permite que o atacante reivindique recompensas e taxas contra registros de ciclo desatualizados, resultando em pagamentos anormalmente elevados.
Contexto
DBXen é um protocolo burn-to-earn: os usuários queimam tokens XEN em troca de recompensas DXN e uma parcela das taxas de protocolo acumuladas. O mecanismo principal funciona em ciclos. Quando um usuário chama burnBatch(), duas coisas acontecem: (1) a quantidade de XEN queimado é registrada sob o endereço do chamador (identificado por _msgSender()), e (2) o contrato XEN retorna ao DBXen via onTokenBurned() para atualizar os registros de ciclo do chamador (ciclo de queima e lastFeeUpdateCycle) para o ciclo atual.
Recompensas e taxas são liquidadas via updateStats(). A recompensa é proporcional à participação do usuário no total de XEN queimado em seu ciclo de queima. A taxa é baseada nas taxas de protocolo cumulativas que acumularam desde o último ciclo registrado do usuário. Ambos os cálculos dependem dos registros de ciclo do usuário estarem atualizados.




Análise de Vulnerabilidade
A causa raiz é a lógica de negócio falha no protocolo DBXen (0xf5c8...2abd). A função _msgSender() verifica se msg.sender é o forwarder. Se for, ela retorna os últimos 20 bytes do calldata, e esse valor retornado pode ser controlado arbitrariamente no contexto do forwarder. No entanto, burnBatch() queima diretamente o XEN mantido por msg.sender. Como resultado, um atacante pode invocar burnBatch() pelo forwarder, fazendo o protocolo queimar o XEN mantido pelo forwarder e atualizar tanto o registro de ciclo de queima quanto o registro de ciclo de atualização de taxas do forwarder para o ciclo atual. Ao mesmo tempo, porém, o protocolo registra a quantidade de XEN queimado sob o endereço correspondente a _msgSender().
Depois disso, o atacante chama claimFees(), que invoca updateStats(). Como os registros de ciclo do endereço _msgSender() nunca foram atualizados (tanto o ciclo de queima quanto lastFeeUpdateCycle permanecem em 0), updateStats() calcula recompensas no ciclo atual e computa taxas acumuladas desde o ciclo 0 - abrangendo todo o histórico de taxas do protocolo. O atacante então lucra chamando claimFees() e claimRewards().

Análise do Ataque
A análise a seguir é baseada na transação 0x914a5a...b808bc37.
-
Passo 1: O atacante primeiro chamou a função
registerDomainSeparator()do contratoForwarder, habilitando chamadas subsequentes aForwarder.execute(). -
Passo 2: O atacante trocou
0,14e18ETHpor13.900.000.000e18XENem um pool Uniswap V2. -
Passo 3: O atacante transferiu
13.900.000.000e18XENpara o contratoForwarder. -
Passo 4: O atacante usou
Forwarder.execute()para aprovar o DBXen a gastar os13.900.000.000e18XENmantidos peloForwarder. -
Passo 5: O atacante usou
Forwarder.execute()para chamarDBXen.burnBatch()e queimou13.900.000.000e18XEN. A quantidade queimada foi registrada sob o endereço0x425D3eC2DCeBE2c04bA1687504D43AFC6be7328d, enquanto durante a execução da queima,XENretornou aoDBXenviaonTokenBurned(), atualizando os registros de ciclo relevantes noForwarder.
-
Passo 6: O atacante usou
Forwarder.execute()para chamarDBXen.claimFees()e obteve65,36e18ETH. -
Passo 7: O atacante usou
Forwarder.execute()para chamarDBXen.claimRewards()e cunhou2.305,4e18DXN.
Conclusão
A causa raiz deste incidente foi que o protocolo DBXen usou de forma inconsistente _msgSender() e msg.sender. Como esses dois valores podem diferir, a contabilidade interna do protocolo ficou inconsistente, o que permitiu que o atacante explorasse a discrepância para obter lucro.
Para reduzir riscos semelhantes no futuro:
- Use
_msgSender()de forma consistente em todos os caminhos de lógica, ou garanta que operações dependentes demsg.sendere a contabilidade dependente de_msgSender()sempre referenciem o mesmo endereço.
Incidente Goose Finance
Resumo
Em 15 de março de 2026, o Goose Finance, um protocolo de yield-farming na BNB Chain, foi explorado por cerca de $8K. A causa raiz foi uma falha na ordem de precificação de cotas em StrategyGooseEgg: deposit() cunha cotas antes de liquidar as recompensas colhidas na contabilidade, portanto o denominador do total de ativos usado para precificação de cotas exclui essas recompensas e é menor do que o valor real. Isso significa que os depositantes recebem mais cotas do que deveriam. Quando withdraw() é chamado, ele aciona uma colheita de recompensas que aumenta o total de ativos, tornando cada cota mais valiosa. Ao repetir depósito e retirada em uma única transação, o atacante cunhou repetidamente cotas com preço acima do real e as resgatou pelo valor corrigido (mais alto), extraindo a diferença como lucro.
Contexto
Goose Finance é um protocolo de yield-farming na BNB Chain onde os fundos dos usuários fluem de um vault para uma estratégia, que aposta ativos no MasterChef para ganhar recompensas EGG.
Os componentes relevantes para este incidente são:
-
VaultChef(0x3f64...): rastreia posições dos usuários e encaminha capital paraStrategyGooseEgg. -
StrategyGooseEgg(0x0980...): mantém a contabilidade no nível da estratégia comsharesTotalewantLockedTotal. -
MasterChef(0xe70e...): recebe ativos apostados e paga recompensasEGG. -
WrappedEgg(0xb815...): encapsulaEGG1:1 emWEGGpara apostas.
Operacionalmente, os depósitos são roteados do VaultChef para StrategyGooseEgg, depois apostados no MasterChef. As retiradas são iniciadas pelo VaultChef e executadas pela estratégia.
Uma expectativa contábil fundamental é que a precificação de cotas deve refletir o total de ativos da estratégia no momento da precificação (principal apostado mais recompensas inativas já mantidas pela estratégia). Em StrategyGooseEgg, no entanto, deposit() cunha cotas antes de _farm() liquidar ativos inativos em wantLockedTotal, enquanto withdraw() pode acionar a colheita de recompensas do MasterChef. Essa ordem é a base da vulnerabilidade analisada abaixo.


Análise de Vulnerabilidade
A causa raiz é uma dessincronização contábil em StrategyGooseEgg (0x0980...b26b) entre a colheita de recompensas e a precificação de cotas.
Em StrategyGooseEgg, a precificação de cotas usa wantLockedTotal como denominador: shares = deposit * sharesTotal / wantLockedTotal. Para que isso seja justo, wantLockedTotal deve refletir todos os ativos que a estratégia realmente possui, incluindo quaisquer recompensas EGG inativas no contrato. No entanto, deposit() cunha cotas antes de _farm() liquidar recompensas inativas em wantLockedTotal. Isso significa que o denominador exclui recompensas não contabilizadas e é menor do que o total real de ativos, fazendo com que o depositante receba mais cotas do que deveria.
Além disso, withdraw() chama MasterChef.withdraw(), que retorna o principal apostado mais as recompensas EGG pendentes para a estratégia. A contabilidade da estratégia apenas subtrai o _wantAmt solicitado de wantLockedTotal, portanto as recompensas colhidas permanecem no saldo da estratégia sem serem refletidas em wantLockedTotal. Isso amplia a lacuna entre os ativos realmente mantidos e o wantLockedTotal registrado, tornando qualquer precificação de cotas de deposit() subsequente ainda mais imprecisa.
Análise do Ataque
A análise a seguir é baseada na transação 0x86efdf...ce316223.
-
Passo 1: O atacante obteve um empréstimo flash de
EGGde dois pares Pancake. -
Passo 2: Primeiro depósito no
VaultChef/StrategyGooseEgg(10.170.000e18EGG). -
Passo 3: Primeira retirada (
12.593.884e18EGG) colhe recompensas doMasterChef;359.561e18EGGé transferido paraStrategyGooseEgge permanece como valor inativo/não contabilizado (R > 0). -
Passo 4: O segundo depósito reutiliza o capital retirado (
12.593.884e18EGG). As cotas são precificadas antes que o valor inativo seja liquidado, portanto este é o passo de supercunhagem. -
Passo 5: A segunda retirada (
12.826.027e18EGG) realiza lucro das cotas supercunhadas (ou seja,232.143EGGacima do valor depositado no passo 4). -
Passo 6: O atacante reembolsa os swaps flash e mantém o spread líquido.
Conclusão
O exploit decorre de uma falha na ordem de precificação de cotas em StrategyGooseEgg: deposit() cunha cotas antes de _farm() atualizar wantLockedTotal, enquanto withdraw() pode colher recompensas do MasterChef que permanecem temporariamente inativas e não contabilizadas. Isso permite que depósitos cunhem cotas contra um denominador desatualizado e depois retirem contra ativos atualizados.
Para reduzir riscos semelhantes no futuro:
-
Liquide recompensas e atualize a contabilidade antes dos cálculos de cunhagem e queima de cotas.
-
Precifique cotas contra um único
totalAssets(apostado + inativo) no ponto exato de cálculo. -
Adicione testes de invariante para
shares_minted <= D * S / (A + R)sob condições de recompensas inativas não nulas.
Sobre a BlockSec
A BlockSec é um provedor completo de segurança blockchain e conformidade de criptoativos. Desenvolvemos produtos e serviços que ajudam nossos clientes a realizar auditoria de código (incluindo contratos inteligentes, blockchain e carteiras), interceptar ataques em tempo real, analisar incidentes, rastrear fundos ilícitos e cumprir obrigações de AML/CFT, ao longo de todo o ciclo de vida de protocolos e plataformas.
A BlockSec publicou múltiplos artigos de segurança blockchain em conferências de prestígio, reportou vários ataques zero-day em aplicações DeFi, bloqueou múltiplos hacks para resgatar mais de 20 milhões de dólares e protegeu bilhões em criptomoedas.
-
Site oficial: https://blocksec.com/
-
Conta oficial no Twitter: https://twitter.com/BlockSecTeam



