Back to Blog

Perdas de ~5,57 milhões USD: exploração de falhas no X100 Freezer e no NEM | Boletim semanal da BlockSec

Code Auditing
29 de outubro de 2026
10 min read
Key Insights
  • Dois incidentes: ~5,57 milhões USD em perdas no escopo da análise, excluindo as extrações posteriores do X100.

  • NEM: falha na liquidação do imposto.

  • X100: novas posições em staking ganharam poder de voto imediato; as propostas não tinham timelock de execução.

Durante a última semana (19/10/2026–25/10/2026), este relatório acompanhou dois incidentes de segurança com perdas estimadas em aproximadamente 5,57 milhões USD. A análise detalhada se concentra na tomada de controle da governança do X100 Freezer na Ethereum.

Data Incidente Tipo Perda estimada*
21/10/2026 NEM Token Falha na lógica de negócios ~820 mil USD
24/10/2026 X100 Freezer Falha no desenho da governança ~4,75 milhões USD

*As perdas são aproximadas. O valor do X100 Freezer cobre a transação representativa analisada abaixo e corresponde à estimativa inicial da Phalcon; o total não inclui extrações posteriores relatadas separadamente. A data do NEM é a data da transação on-chain; o alerta público foi publicado em 22 de outubro [1].

  • X100 Freezer: O incidente mostra o risco combinado da elegibilidade para a governança com efeito imediato e da ausência de um timelock para a execução: o atacante usou fundos obtidos por empréstimo-relâmpago para comprar e congelar tokens, conquistou imediatamente a maioria das cadeiras no Senado e aprovou e executou uma proposta maliciosa para o tesouro na mesma transação.

O melhor auditor de segurança para Web3

Valide o desenho, o código e a lógica de negócios antes do lançamento

Destaque da semana: X100 Freezer

Em 24/10/2026, o X100 Freezer, um sistema on-chain de staking e gestão de liquidez na Ethereum, foi explorado, com perdas de aproximadamente 4,75 milhões USD na transação examinada aqui. Uma falha no desenho da governança permitia que saldos congelados recém-adquiridos conferissem cadeiras no Senado imediatamente, sem um timelock entre a aprovação e a execução de uma proposta. O atacante garantiu duas das três cadeiras, direcionou uma troca de ativos do tesouro para um pool sob seu controle e vendeu parte dos tokens recuperados para pagar o empréstimo-relâmpago e obter lucro [2].

Contexto

Os usuários do X100 congelam tokens X em posições de staking divididas por níveis para receber recompensas. O contrato Freezer em 0x79f3...2a46 também gerencia a liquidez do projeto na Uniswap V3/V4 e na PancakeSwap V3. Por meio de DexTreasury, ele herda o contrato de governança Senate; o Senado decide as operações do tesouro por meio de propostas e votos.

O ponto de entrada público freeze() transfere os tokens do usuário para o contrato e, em seguida, chama a função privada _freeze() para criar uma posição de staking e atualizar sua contabilização. _tierTotal[owner][tier] registra a quantidade congelada de cada conta em cada nível. _freeze() atualiza esses saldos e notifica o sistema de governança por meio de _onStakeChanged(owner):

function _freeze(address owner, uint8 tier, uint256 amount) private returns (uint256 id) {
    _settle(owner);

    Account storage account = _accounts[owner];
    if (account.firstFreezeAt == 0) {
        account.firstFreezeAt = block.timestamp;
    }

    id = _create(owner, tier, amount, block.timestamp, block.timestamp);

    _tierTotal[owner][tier] += amount;
    totalFrozen += amount;
    totalFrozenIn[tier] += amount;
    _onStakeChanged(owner);

    emit Frozen(id, owner, tier, amount);
}

Para entrar na lista de candidatos ao Senado, uma conta chama applyForSenate(). Isso invoca _register(), que registra a candidatura, cobra a taxa de candidatura e chama o mesmo gancho de atualização do stake:

function _register(address account) internal {
    require(!_registered[account], AlreadyRegistered(account));

    _registered[account] = true;
    _collectCandidacyFee(account);

    emit Registered(account);

    _onStakeChanged(account);
}

O gancho ignora contas não registradas. Para as contas registradas, ele mantém uma lista classificada pelos saldos congelados, inserindo ou movendo contas por meio de _link(). isSenator() identifica como senadores as primeiras senateSize contas dessa lista. O sistema comporta de 3 a 21 cadeiras, cada uma com direito a um voto. Os tokens congelados estão sujeitos a um prazo para saque, calculado por _unfreezeAt() a partir do timestamp frozenAt da posição e do nível de staking.

Um senador apresenta uma operação de tesouro permitida por meio de propose(), que registra a proposta e atribui automaticamente um voto favorável do proponente. Os demais senadores votam por meio de vote(), e _tally() conta os votos favoráveis entre os ocupantes atuais das cadeiras. A proposta registra seu horário de criação e um prazo final determinado por votingPeriod, cujo padrão é de três dias.

Funções do tesouro como v3Swap() são alvos de proposta permitidos em DexTreasury._isProposable(). Seu modificador onlySenate exige que a chamada venha do próprio contrato. O fluxo de execução faz essa chamada a si mesmo usando os dados da proposta aprovada. Depois, Freezer._afterExecute() verifica se o saldo restante de X cobre totalFrozen, preservando o principal congelado agregado.

Análise da vulnerabilidade

A falha no desenho da governança do Freezer consistia na ausência de um período de espera antes que o stake recém-adquirido pudesse conferir autoridade no Senado e de um timelock antes da execução de uma proposta aprovada.

Primeiro, o stake usado para a classificação vem diretamente dos saldos congelados atuais. _stakeOf() chama frozenOf(), que soma _tierTotal sem verificar a antiguidade do stake nem consultar um saldo histórico:

function _stakeOf(address account) internal view override returns (uint256) {
    return frozenOf(account);
}

function frozenOf(address owner) public view returns (uint256 total) {
    total = 0;
    for (uint8 tier = 0; tier < TIERS; ++tier) {
        total += _tierTotal[owner][tier];
    }
}

Os fluxos de depósito e registro mostrados acima atualizam a elegibilidade na mesma sequência de chamadas. Embora _freeze() registre timestamps para a posição, as verificações de classificação e de condição de senador não os utilizam para impor um período mínimo de manutenção. Assim, um novo candidato com fundos suficientes pode obter uma cadeira e exercer seus direitos de apresentar propostas e votar na mesma transação. O prazo para saque dos tokens não adia esses direitos de governança.

Segundo, o período de votação de três dias determina apenas quando uma proposta expira. _state() retorna Open assim que a proposta passa a existir, e ela permanece aberta até a execução, o cancelamento ou a expiração. A verificação da maioria independe do tempo decorrido:

function _state(Proposal storage proposal) private view returns (ProposalState) {
    if (proposal.executed) {
        return ProposalState.Executed;
    }
    if (proposal.cancelled) {
        return ProposalState.Cancelled;
    }
    if (block.timestamp > proposal.deadline) {
        return ProposalState.Expired;
    }
    return ProposalState.Open;
}

function _isPassed(uint256 support) private view returns (bool) {
    return support * 2 > senateSize;
}

execute() aceita uma proposta aberta assim que os votos favoráveis excedem a metade de senateSize. Antes de chamar a operação do tesouro, ele não verifica nem um intervalo mínimo desde createdAt nem um período de espera após a aprovação:

function execute(uint256 id) external {
    Proposal storage proposal = _requireOpen(id);

    uint256 size = senateSize;
    (uint256 support, address[] memory seats) = _tally(id);
    require(_isPassed(support), NotPassed(id, support, size));

    proposal.executed = true;

    (bool ok, bytes memory result) = address(this).call(proposal.data);
    if (!ok) {
        assembly ("memory-safe") {
            revert(add(result, 32), mload(result))
        }
    }

    _afterExecute(id);

    emit ProposalExecuted(id, _msgSender(), support, size, seats);
}

A chamada a si mesmo satisfaz onlySenate, portanto a verificação de acesso ao tesouro não acrescenta nenhum atraso à execução. A verificação final do principal congelado não restringe quando a proposta é executada nem impõe um retorno mínimo para a troca de ativos do tesouro. Essas condições permitem que uma maioria recém-formada autorize e execute uma operação de tesouro em uma única transação.

Análise do ataque

A análise a seguir se baseia na transação 0x38c608...4d81d0.

  • Etapa 1: O atacante usou fundos obtidos por empréstimo-relâmpago para comprar tokens X e os distribuiu entre dois contratos sob seu controle. Os fundos emprestados financiaram a compra dos tokens que estabeleceriam as duas posições de staking.

  • Etapa 2: Cada contrato sob controle do atacante congelou seus tokens X no Freezer e chamou applyForSenate(). O rastreamento mostra que ambos os contratos receberam um evento Ranked após o registro. Seus saldos congelados garantiram duas cadeiras no Senado dentro da transação. No momento do ataque, o Senado tinha três cadeiras, portanto o controle de duas delas proporcionava a maioria necessária para aprovar uma proposta de tesouro.

  • Etapa 3: O atacante criou um pool X/USDT na PancakeSwap V3 e forneceu sua liquidez. Um dos contratos sob seu controle apresentou uma proposta de troca de ativos do tesouro, registrando automaticamente um voto favorável; o outro registrou o segundo voto favorável. Com o limiar de maioria atingido, o Freezer executou a proposta 7. A chamada a v3Swap() especificava 400.000 X como entrada e amountOutMinimum = 0. O tesouro recebeu apenas cerca de 35,68 USDT. O rastreamento registra votesFor = 2 e senateSize = 3, mostrando que a maioria conquistada autorizou a operação.
  • Etapa 4: O atacante retirou a liquidez do pool que acabara de criar na PancakeSwap V3 para recuperar os tokens X do tesouro. Vendeu parte desses tokens por meio do pool X/USDT já existente na Uniswap V3 e pagou o empréstimo-relâmpago. Os recursos para o pagamento vieram da venda subsequente, e não de um saque imediato das posições de staking congeladas.

Comece a usar o Phalcon Explorer

Explore as transações para agir com conhecimento

Experimente gratuitamente agora

Conclusão

O incidente resultou de uma falha no desenho da governança: os saldos congelados atuais conferiam autoridade imediatamente, e propostas aprovadas podiam ser executadas sem um timelock. O atacante combinou essas condições para conquistar uma maioria e usá-la antes do vencimento do empréstimo-relâmpago. O tesouro então vendeu 400.000 X por cerca de 35,68 USDT por meio do pool sob controle do atacante na PancakeSwap V3. O atacante retirou a liquidez desse pool para recuperar os tokens do tesouro, vendeu parte deles por meio do pool X/USDT separado e já existente na Uniswap V3 e usou os recursos obtidos para pagar o empréstimo-relâmpago e ficar com um lucro.

A governança deve exigir um tempo mínimo de permanência em staking ou determinar a elegibilidade para as cadeiras e os direitos de voto a partir de um snapshot histórico dos saldos, obtido em um bloco anterior à transação atual. Isso impede que posições financiadas dentro da transação autorizem imediatamente movimentações do tesouro. Um timelock entre a aprovação e a execução deve impedir que toda a sequência de tomada de controle e extração seja concluída em uma única transação e dar tempo para analisar ou cancelar uma proposta maliciosa. Esses controles abordam etapas distintas do fluxo de governança e devem ser avaliados em conjunto durante uma auditoria de contratos inteligentes.

Referências

[1] Phalcon da BlockSec: análise do incidente com o NEM Token

[2] Phalcon da BlockSec: análise do incidente de governança do X100 Freezer

Verificação de segurança gratuita

Uma análise rápida de segurança com nosso mecanismo interno de análise automatizada.

Faça uma verificação gratuita

Sobre a BlockSec

A BlockSec é uma fornecedora completa de segurança blockchain e conformidade cripto. Desenvolvemos produtos e serviços que ajudam clientes a realizar auditorias de código (incluindo contratos inteligentes, blockchains 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 diversos artigos sobre segurança blockchain em conferências de prestígio, relatou vários ataques de dia zero contra aplicações DeFi, bloqueou diversas invasões para resgatar mais de 20 milhões USD e protegeu bilhões em criptomoedas.

Sign up for the latest updates
Perdas de ~3,87 milhões USD: ataques à Autheo Network e à UNCX | Resumo semanal da BlockSec
Security Insights

Perdas de ~3,87 milhões USD: ataques à Autheo Network e à UNCX | Resumo semanal da BlockSec

Este relatório semanal aborda 3 incidentes de segurança no período de 12/10/2026–18/10/2026, com perdas totais estimadas em aproximadamente 3,87 milhões USD. A Autheo Network sofreu um comprometimento de chave privada com perdas de cerca de 1,76 milhões USD, a Qubic Wallet perdeu cerca de 1,30 milhões USD devido à geração de seeds fracas, e os contratos Smart Token Vesting V2 da UNCX Network sofreram um erro contábil de cerca de 807 mil USD nas redes Ethereum, BNB Chain, Base e Robinhood Chain. A análise em destaque da UNCX explica como um cálculo incorreto do total de cotas misturou parcelas de vesting criadas com diferentes proporções entre tokens e cotas, permitindo saques acima do devido de pools compartilhados.

~US$ 542 mil perdidos: ataque ao MakerDaoBot | Boletim semanal da BlockSec
Security Insights

~US$ 542 mil perdidos: ataque ao MakerDaoBot | Boletim semanal da BlockSec

O relatório cobre 1 incidente no Ethereum (05–11/10/2026), com perda estimada de US$ 542 mil. Um adaptador malicioso obteve acesso aos saldos MakerDAO via função desprotegida do MakerDaoBot, liquidou 4 leilões ETH-A e converteu 200 ETH-A em WETH, depois enviados como ETH ao atacante.

~$418M Perdidos: Explorações do Bitget e NEAR Intents | BlockSec Weekly
Security Insights

~$418M Perdidos: Explorações do Bitget e NEAR Intents | BlockSec Weekly

Relatório quinzenal (21/9–4/10/2026): 8 incidentes de segurança, ~US$418,4M perdidos em Ethereum, BNB Chain, Solana, Bitcoin, TRON, XRP Ledger, Zcash, Avalanche, NEAR. Destaca vulnerabilidade de US$387,5M na Bitget e falha de US$3,87M na NEAR Intents.

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit
Perdas de ~5,57 milhões USD: exploração de falhas no X100 Freezer e no NEM | Boletim semanal da BlockSec