Back to Blog

約387万 USDの損失:Autheo NetworkとUNCXへのハッキング | BlockSecウィークリー

Code Auditing
2026年10月22日
11 min read
Key Insights
  • 本レポートでは、注目すべきセキュリティインシデント3件を取り上げます。推定損失総額は約387万 USDです。インシデントには、秘密鍵の侵害、権利確定に関する会計処理の誤り、ウォレットのシード生成の脆弱さが関わっていました。

  • UNCX NetworkのSmart Token Vesting V2に関するインシデントは、Ethereum、BNB Chain、Base、Robinhood Chainにまたがる10種類の資産に影響を及ぼしました。集計シェアの計算に不備があり、トークンとシェアの比率が異なる時点で作成された権利確定トランシェを混在させたことで、実現または移転された価値として約80.7万 USDを引き出すことが可能になりました。

  • プールされた資産の会計処理では、各トランシェのトークン数量、シェアの算定基準、権利確定の進捗の関係を維持する必要があります。これらを単一の比率でまとめると、あるポジションが共有残高から過剰に引き出し、ほかのポジションに充てられる資産が減少する可能性があります。

過去1週間(2026年10月12日–2026年10月18日)に発生した注目すべきセキュリティインシデントのうち、以下の3件を取り上げます。推定損失額の合計は約387万 USDです。

日付 インシデント 種類 推定損失額
2026年10月12日 Autheo Network 秘密鍵の漏洩 約176万 USD
2026年10月14日 UNCX Network 会計処理上の誤り 約80.7万 USD
2026年10月18日 Qubic Wallet 脆弱なシード生成 約130万 USD

損失額は実現価値に基づく推定値です。

  • UNCX Network: 集計シェアの計算に欠陥があり、今週のインシデントの中でコントラクトの会計処理に関する教訓を最も明確に示しているため、詳しく分析します。

無料セキュリティスキャン

自社開発の自動分析エンジンで、セキュリティを手軽にチェックできます。

無料でスキャン

今週の注目インシデント:UNCX Network

2026年10月14日、攻撃者はEthereum、BNB Chain、Base、Robinhood Chain上のUNCX NetworkのSmart Token Vesting V2コントラクトを悪用しました。このインシデントでは、確認された11件の資産流出トランザクションで10種類の資産が被害を受け、実現または移転された価値は約80.7609万 USDに上りました [1]。根本原因は、トークンとシェアの交換比率が異なる時点で作成されたベスティングのトランシェを混ぜ合わせた、集計シェアの計算上の欠陥でした。その結果、ポジション単位の記録とグローバルなシェア供給量が乖離し、攻撃者が管理するポジションから、攻撃者が拠出した量を超えるトークンを引き出せるようになりました。

背景

UNCX NetworkはマルチチェーンのDeFiインフラプロバイダーです。同社のSmart Token Vesting V2では、プロジェクトがERC-20トークンを期間に応じたベスティングスケジュールに従ってロックできます。各スケジュールはベスティングIDで識別され、トークン、作成者、受益者、総量、リリース済みの量、1つ以上のアンロック対象トランシェが記録されます。追加拠出が可能なソフトポジションには、作成後にトランシェを追加できます。また、その作成者は未ベスト分をキャンセルできます。

同じトークンのポジションはVestingManager内の残高を共有し、プロトコルはシェアを使って各ポジションがその残高のどれだけを保有するかを決定します。したがって、会計処理には関連する2つの層があります。

Global pool, per token
  create / topUp: receive tokens and mint shares
  release: convert releasable shares into tokens
  _totalTokenShares[token]: active shares across all positions

Position record, per vesting ID
  _depositedShares[id]: share basis assigned to the position
  totalAmount: token amount represented by its tranches
  released: shares already paid to the beneficiary

リリース時、マネージャーはまずスケジュールのうちベスト済みの割合を計算します。_depositedShares[vestingId]を使って、その割合に相当するtotalAmountをベスト済みシェアに換算し、releasedを差し引いた結果をreleasableSharesとします。以下の式で、tokenBalanceは、当該スケジュールのトークンについてマネージャーが現在保有するERC-20残高であり、そのトークンの全ポジションで共有されます。一方、_totalTokenShares[token]は対応する有効シェアのグローバル供給量です。支払われるトークン量は、両者の比率によって決まります。

amount = releasableShares * tokenBalance / _totalTokenShares[token]

ベスティング関数を通じた入金では、トークン残高とシェア供給量の両方が増えます。マネージャーへのERC-20の直接送金ではトークン残高だけが変わるため、各シェアが表すトークン量が変化します。このシェアモデルでプールされたポジションを扱うには、ライフサイクルのすべての操作でポジションの記録とグローバル供給量の整合性を保つ必要があります。

脆弱性分析

影響を受けたEthereum上のVestingManager(0xA98F...99F5)には、release()、topUpVesting()、cancel()を通じて悪用可能になる、集計シェアの計算上の欠陥があります。ほかの3つのネットワークにも、同等の影響を受けるデプロイが存在します。

以下の分析では、状態の変化を比較しやすくするため、D、R、Vを略記号として導入します。これらの記号はコントラクトのコードには登場しません。表では、各記号に対応するコントラクトの変数または式を示します。対応する値は、2種類の数量に分かれます。

記号 コントラクトの変数/式 数量の種類 意味
D _depositedShares[vestingId] シェア数 ポジションについて記録されたすべての入金に割り当てられた累積シェア基準値
R schedule.released シェア数 受益者に支払われた累積シェア数
- schedule.totalAmount トークン量 ポジションの現在のトランシェ全体について記録されたトークン総量
- vestedAmount トークン量 現時点で、それらのトランシェに従ってベスト済みとなったtotalAmountの部分
V vestedShare シェア数 単一の混合されたベスト済みトークン比率をDに適用して計算した累積ベスト済みシェア数

release()では、コントラクトはreleasableSharesを計算し、schedule.releasedを増やし、同じ数量を_totalTokenShares[schedule.token]から差し引きます。_depositedShares[vestingId]は減らしません。したがって、リリース後、そのポジションがグローバル供給量に寄与する有効シェアはD - Rだけですが、保存された基準値はDのままです。

function release(uint256 vestingId) external nonReentrant {
    ...
    uint256 releasableShares = _getReleasableShares(vestingId);
    uint256 balance = IERC20(schedule.token).balanceOf(address(this));
    uint256 amount =
        (releasableShares * balance) / _totalTokenShares[schedule.token];

    schedule.released += releasableShares;
    _totalTokenShares[schedule.token] -= releasableShares;
    IERC20(schedule.token).safeTransfer(msg.sender, amount);
}

cancel()は、ポジションの集計シェア基準値に単一の混合されたベスティング比率を適用します。まずgetVestedAmount(vestingId)を通じてvestedAmountを計算し、次にトークン建てのベスト済み割合をV = (vestedAmount * D) / totalAmountとしてシェアに換算します。最後に、この関数はD - Vを、そのポジションから除去できる未ベスト済みシェアとして扱います。Vは累積値であり、過去の支払い後に残っているベスト済みシェアではありません。

function cancel(uint256 vestingId) external nonReentrant {
    ...
    uint256 vestedAmount = getVestedAmount(vestingId);
    uint256 remainingAmount = schedule.totalAmount - vestedAmount;

    uint256 vestedShare =
        vestedAmount * _depositedShares[vestingId] / schedule.totalAmount;
    uint256 sharesToRemove =
        _depositedShares[vestingId] - vestedShare;
    _totalTokenShares[schedule.token] -= sharesToRemove;

    _depositedShares[vestingId] = vestedShare;
    schedule.totalAmount = vestedAmount;
    schedule.cancelled = true;

    IERC20(schedule.token).safeTransfer(schedule.creator, remainingAmount);
}

欠陥は、この混合計算そのものにあります。各トランシェには、それぞれ固有のトークン量、ベスティングの進捗、そして追加時に適用されたプール比率で発行されたシェア数があります。そのため、ベスト済みシェアはトランシェごとに計算してから合計すべきです。しかしコントラクトは、まずトークン量とシェア基準値を集計し、その後、結合されたポジションに単一のベスティング比率を適用します。保存するDとtotalAmountがそれぞれ1つだけだからです。この2つの方法が同じ結果になるのは、各トランシェのトークン当たりのシェア比率か、ベスティングの進捗が同じ場合に限られます。追加拠出前にトークンを直接送金するとプール比率が変わるため、新しいトランシェに付与されるトークン当たりのシェア数は、元のトランシェよりはるかに少なくなります。その状態で両トランシェに単一の混合ベスティング比率を適用すると、両者のベスト済みシェアの合計を表さないVが算出され得ます。

Rはポジションの累積ベスト済みシェアからすでに支払われているため、整合性のあるスケジュールはR <= Vを満たす必要があります。この不等式に違反することが、混合計算の問題を直接示しています。コードはポジションごとの有効シェア残高を別途管理せず、D - Vをグローバルな_totalTokenSharesから直接差し引きます。ほかのポジションが1000シェアを拠出し、このポジションの値がD = 100とR = 80であるとします。キャンセル前のグローバル供給量には1,000 + (D - R) = 1,020シェアが含まれます。混合計算の結果がV = 60になった場合、cancel()はD - V = 40を差し引き、グローバルなシェアを980だけ残します。これは、ほかのポジションが拠出した1000シェアより20少ない数です。グローバル供給量にこのポジションの有効シェア20しか含まれていなければ、40を差し引くとアンダーフローが発生して処理がリバートします。過大な差し引きが成功するのは、共有プールにほかのポジションが拠出したシェアが含まれているからです。その後、関数は_depositedShares[vestingId] = 60を保存しますが、schedule.releasedは80のままです。その結果、ポジションの記録はD < Rというあり得ない状態になります。

このコードはR <= Vを強制せず、sharesToRemoveをポジションの有効シェア以下にも制限しません。このため、キャンセルによって、すでにグローバル供給量に含まれていない過去のシェアを差し引けます。同時に、プールのシェア比率を使って返金額を換算することなく、totalAmount - vestedAmountをトークン単位で直接送金します。キャンセル自体で過大な支払いが発生するわけではありません。キャンセルはグローバルなシェア供給量を、各ポジションに記録された有効シェアの合計より少なくするだけであり、後の過大な償還が起こる条件を作ります。

攻撃分析

以下では、Ethereum上の代表的なトランザクション0x352065...c23823を分析します。攻撃コントラクトは、このトランザクション内で5種類のトークンに対して同じ基本手順を実行し、それぞれにフラッシュ流動性を使用しました。

  • ステップ1: 攻撃者は、作成時点ですぐにベスト済みとなる小規模なポジション#5058と、同じくすぐにベスト済みとなる、はるかに大規模な追加拠出可能なソフトポジション#5059および#5060を作成しました。小規模なポジションは最後の引き出しに使うために残し、大規模なポジションではグローバルな会計処理を歪めるために必要な過去のシェア記録を作りました。

  • ステップ2: 攻撃者は2つの大規模なポジションをリリースしました。当初のプール比率はほぼ1:1で、各リリースでは純入金額とほぼ同量が戻りました。対応するシェアは_totalTokenSharesから除かれましたが、元の値はポジション#5059と#5060の_depositedSharesの記録に残りました。リリース済みの量が記録されたのは、各スケジュールに別途設けられたreleasedフィールドだけでした。

  • ステップ3: 攻撃者はVestingManagerにトークンを直接送金しました。これにより、リリース済みのシェアを戻さずにトークン残高を回復させたため、残存する各シェアが表すトークン量が急増しました。

  • ステップ4: 攻撃者は、リリース済みの大規模なポジションに追加拠出しました。追加拠出には、上昇後のシェア当たりトークン比率が適用されたため、相当量のトークンを入金しても、発行された新しいシェアは少数でした。この時点で、これらのポジションには、過去に記録された大きな基準値と、少量の有効シェアの拠出が併存していました。

  • ステップ5: 攻撃者は、追加拠出後の2つのポジションをキャンセルしました。各キャンセルでは、入金に対応するシェアの履歴を集計した値に、単一の混合ベスティング比率が適用されました。再計算されたvestedShareはリリース済みのシェア数を下回ったため、sharesToRemoveがそのポジションの有効シェアの拠出量を上回りました。各ポジションが追加拠出時に加えた有効シェアは少量だったにもかかわらず、グローバル供給量はポジション当たり約5.0e25の実体のないシェア分だけ減少しました。

  • ステップ6: 分母が大幅に過小評価された状態で、攻撃者は残しておいた小規模なポジションをリリースしました。例に挙げたトークンでは、約5.73e22の生の単位での純入金額から、約1.07e26の生の単位が引き出されました。これは入金額の約1,873倍です。攻撃者は、歪められた比率を利用して作成とリリースを繰り返し、フラッシュ流動性を返済しました。

公式インシデントレポートでは、確認された11件の資産流出トランザクション全体で同じパターンが確認されました。一部のパターンは単一のトランザクション内で完結し、ほかのパターンでは関連する別のトランザクションで最後のリリースが行われました。UNCXは、攻撃者の元本、一時的なフラッシュ流動性の取引量、返還された資産を除外した後の、実現または移転された収益から約80.7609万 USDという数値を算出しました [1]。

Phalcon Explorerを使い始める

トランザクションを詳しく調べ、適切に判断する

今すぐ無料で試す

結論

根本原因は、集計シェアの会計処理における欠陥でした。プロトコルは、トークンとシェアの交換比率が異なる時点で作成されたトランシェを結合し、その集計シェア基準値に単一のベスティング比率を適用しました。これにより累積ベスト済みシェアが誤算され、ポジションが現在拠出している量を超えるシェアを除去できるようになり、ポジション単位の記録とグローバルなシェア供給量が乖離しました。攻撃者は過小評価されたグローバル供給量を悪用し、ほかのベスティングポジションへの支払いに必要な共有残高からトークンを引き出しました。

変動するシェア比率で後から入金できる会計モデルでは、各トランシェを単一の比率で混合するのではなく、それぞれのトークン量、シェア基準値、ベスティングの進捗を保持すべきです。また、累積支払量が累積ベスト済みシェアを決して超えないこと、およびポジションが自身の有効シェア拠出量を超えてシェアを除去できないことを強制すべきです。

参考資料

[1] UNCX Network Smart Token Vesting V2インシデントレポート

Web3に最適なセキュリティ監査機関

ローンチ前に設計、コード、ビジネスロジックを検証

Sign up for the latest updates
約54万2,000ドルの損失:MakerDaoBotへの攻撃 | BlockSec週間ニュース
Security Insights

約54万2,000ドルの損失:MakerDaoBotへの攻撃 | BlockSec週間ニュース

本レポートは2026/10/05~10/11にEthereumで発生したセキュリティ事故1件を扱う。推定損失は約54.2万ドル。攻撃コントラクトは悪意あるアダプターを展開し、アクセス制御のないMakerDaoBot関数に渡して、ボット内部のMakerDAO残高への操作権限を付与させた。アダプターは旧ETH-Aオークション4件を決済し、ETH-A担保200単位をWETHに変換。攻撃コントラクトがWETHをETHに戻し、攻撃者へ200 ETHを送金した。

約4.18億ドル損失:Bitget、NEAR Intentsのエクスプロイト | BlockSec Weekly
Security Insights

約4.18億ドル損失:Bitget、NEAR Intentsのエクスプロイト | BlockSec Weekly

本隔週セキュリティレポートは、2026年9月21日から10月4日までの8件のインシデントを記録し、Ethereum、BNB Chain、Solana、Bitcoin、TRON、XRP Ledger、Zcash、Avalanche、NEARなどで約4億1840万ドルの損失が発生。詳細分析では、Bitgetの3.875億ドルのサードパーティ製品脆弱性と、NEAR Intentsの387万ドルの返金検証欠陥および状態ロールバック欠落を取り上げる。

BitgetのオフチェーンでのUSD 3億8,750万ドル流出:鍵とコントラクトを超えて
Security Insights

BitgetのオフチェーンでのUSD 3億8,750万ドル流出:鍵とコントラクトを超えて

2026年9月24日、攻撃者がサードパーティ製セキュリティ製品の脆弱性を悪用し内部認証情報を取得、出金命令を偽造。Ethereum、他のEVMネットワーク、XRP Ledger、Zcash、TRON上のBitget運用ウォレットから約3億8750万ドルが流出。秘密鍵とコールドウォレットは無事。本稿は攻撃経路と資金フロー、即時換金とエコシステムの回復対応を整理し、組織向けの体系的な多層防御策を提案、認可済みブロックチェーン侵入テストによる層間検証手法を解説する。

Best Security Auditor for Web3

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

BlockSec Audit