In der vergangenen Woche (19.10.2026–25.10.2026) erfasste dieser Bericht zwei Sicherheitsvorfälle mit geschätzten Verlusten von insgesamt etwa 5,57 Millionen USD. Die detaillierte Analyse konzentriert sich auf die Übernahme der Governance von X100 Freezer auf Ethereum.
| Datum | Vorfall | Art | Geschätzter Verlust* |
|---|---|---|---|
| 21.10.2026 | NEM Token | Fehlerhafte Geschäftslogik | ~820 Tausend USD |
| 24.10.2026 | X100 Freezer | Fehlerhaftes Governance-Design | ~4,75 Millionen USD |
*Die Verluste sind Näherungswerte. Der Wert für X100 Freezer bezieht sich auf die unten analysierte, repräsentative Transaktion und entspricht der ersten Schätzung von Phalcon; separat gemeldete spätere Entnahmen sind in der Gesamtsumme nicht enthalten. Das Datum für NEM ist das Datum der On-Chain-Transaktion; die öffentliche Warnmeldung wurde am 22. Oktober veröffentlicht [1].
- X100 Freezer: Der Vorfall zeigt das Zusammenwirken zweier Risiken: sofort wirksamer Berechtigung zur Mitwirkung an der Governance und eines fehlenden Timelocks für die Ausführung. Der Angreifer kaufte und sperrte Token mit Mitteln aus einem Flash Loan, erlangte sofort die Mehrheit der Senatssitze und brachte innerhalb derselben Transaktion einen bösartigen Treasury-Vorschlag zur Abstimmung und Ausführung.
Der beste Sicherheitsprüfer für Web3
Design, Code und Geschäftslogik vor dem Start prüfen lassen
Schwerpunkt der Woche: X100 Freezer
Am 24.10.2026 wurde X100 Freezer, ein On-Chain-System für Staking und Liquiditätsmanagement auf Ethereum, in der hier untersuchten Transaktion um etwa 4,75 Millionen USD ausgenutzt. Aufgrund eines fehlerhaften Governance-Designs verliehen neu erworbene gesperrte Guthaben sofort Senatssitze; zwischen der Genehmigung eines Vorschlags und seiner Ausführung lag kein Timelock. Der Angreifer sicherte sich zwei von drei Sitzen, lenkte einen Treasury-Swap in einen von ihm kontrollierten Pool und verkaufte einen Teil der zurückerlangten Token, um den Flash Loan zurückzuzahlen und einen Gewinn zu erzielen [2].
Hintergrund
Nutzer von X100 sperren X-Token in gestaffelten Staking-Positionen, um Belohnungen zu erhalten. Der Freezer-Contract unter 0x79f3...2a46 verwaltet außerdem die Liquidität des Projekts auf Uniswap V3/V4 und PancakeSwap V3. Über DexTreasury erbt er vom Governance-Contract Senate; der Senat entscheidet mittels Vorschlägen und Abstimmungen über Treasury-Operationen.
Der öffentliche Einstiegspunkt freeze() überträgt die Token des Nutzers an den Contract und ruft dann die private Funktion _freeze() auf, um eine Staking-Position anzulegen und deren Buchführung zu aktualisieren. _tierTotal[owner][tier] erfasst für jedes Konto die gesperrte Menge in jeder Stufe. _freeze() aktualisiert diese Guthaben und benachrichtigt das Governance-System über _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);
}
Um in die Liste der Senatskandidaten aufgenommen zu werden, ruft ein Konto applyForSenate() auf. Dadurch wird _register() aufgerufen; die Funktion erfasst die Registrierung, zieht die Kandidaturgebühr ein und ruft denselben Hook zur Aktualisierung des Stakes auf:
function _register(address account) internal {
require(!_registered[account], AlreadyRegistered(account));
_registered[account] = true;
_collectCandidacyFee(account);
emit Registered(account);
_onStakeChanged(account);
}
Der Hook überspringt nicht registrierte Konten. Für registrierte Konten verwaltet er eine nach gesperrten Guthaben geordnete Liste und fügt Konten über _link() ein oder verschiebt sie. isSenator() bestimmt die ersten senateSize Konten dieser Liste zu Senatoren. Das System unterstützt 3 bis 21 Sitze, wobei jeder Sitz eine Stimme hat. Für gesperrte Token gilt eine Frist bis zur Auszahlung, die _unfreezeAt() anhand des Zeitstempels frozenAt der Position und der Staking-Stufe berechnet.
Ein Senator reicht über propose() eine zulässige Treasury-Operation ein. Dabei wird der Vorschlag erfasst und automatisch die befürwortende Stimme des Antragstellers abgegeben. Andere Senatoren geben ihre Stimmen über vote() ab; _tally() zählt die befürwortenden Stimmen unter den aktuellen Sitzen. Für den Vorschlag werden sein Erstellungszeitpunkt und eine durch votingPeriod bestimmte Frist erfasst, die standardmäßig drei Tage beträgt.
Treasury-Funktionen wie v3Swap() sind in DexTreasury._isProposable() als Ziele von Vorschlägen zugelassen. Ihr Modifier onlySenate verlangt einen Aufruf durch den Contract selbst. Im Ausführungspfad erfolgt dieser Selbstaufruf anhand der genehmigten Vorschlagsdaten. Anschließend prüft Freezer._afterExecute(), ob das verbleibende Guthaben an X mindestens totalFrozen beträgt, sodass die insgesamt gesperrte Einlage erhalten bleibt.
Analyse der Schwachstelle
Dem fehlerhaften Governance-Design des Freezer fehlten sowohl eine Verzögerung, bevor neu erworbene Staking-Bestände Senatsbefugnisse verleihen konnten, als auch ein Timelock vor der Ausführung eines genehmigten Vorschlags.
Erstens stammt der für die Rangfolge maßgebliche Stake unmittelbar aus den aktuellen gesperrten Guthaben. _stakeOf() ruft frozenOf() auf, das die Werte in _tierTotal summiert, ohne das Alter des Stakes zu prüfen oder ein historisches Guthaben auszulesen:
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];
}
}
Die oben gezeigten Pfade für Einzahlung und Registrierung aktualisieren die Berechtigung innerhalb derselben Aufrufsequenz. _freeze() erfasst zwar Zeitstempel für die Position, doch die Prüfungen der Rangfolge und der Senatoreneigenschaft verwenden sie nicht, um eine Mindesthaltedauer durchzusetzen. Ein neuer Kandidat mit ausreichenden Mitteln kann daher innerhalb derselben Transaktion einen Sitz erhalten und seine Vorschlags- und Stimmrechte ausüben. Die Frist bis zur Auszahlung der Token verzögert diese Governance-Rechte nicht.
Zweitens bestimmt die dreitägige Abstimmungsfrist lediglich, wann ein Vorschlag abläuft. _state() gibt Open zurück, sobald der Vorschlag existiert; dieser Status bleibt bis zur Ausführung, Stornierung oder zum Ablauf bestehen. Die Mehrheitsprüfung ist unabhängig von der verstrichenen Zeit:
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() akzeptiert einen offenen Vorschlag, sobald die Zahl der befürwortenden Stimmen mehr als die Hälfte von senateSize beträgt. Vor dem Aufruf der Treasury-Operation prüft die Funktion weder, ob seit createdAt eine Mindestzeit vergangen ist, noch, ob nach der Genehmigung eine Verzögerung eingehalten wurde:
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);
}
Der Selbstaufruf erfüllt onlySenate, sodass die Zugriffskontrolle der Treasury keine Ausführungsverzögerung bewirkt. Die abschließende Prüfung der gesperrten Einlage schränkt weder den Ausführungszeitpunkt des Vorschlags ein noch setzt sie einen Mindestertrag für den Treasury-Swap durch. Unter diesen Bedingungen kann eine neu erlangte Mehrheit eine Treasury-Operation innerhalb einer einzigen Transaktion genehmigen und ausführen.
Analyse des Angriffs
Die folgende Analyse basiert auf der Transaktion 0x38c608...4d81d0.
-
Schritt 1: Der Angreifer kaufte mit Mitteln aus einem Flash Loan
X-Token und verteilte sie auf zwei von ihm kontrollierte Contracts. Die geliehenen Mittel finanzierten den Tokenkauf, mit dem die beiden Staking-Positionen eingerichtet werden sollten. -
Schritt 2: Jeder der beiden kontrollierten Contracts sperrte seine
Xim Freezer und riefapplyForSenate()auf. Der Trace zeigt, dass beide Contracts nach ihrer Registrierung einRanked-Ereignis erhielten. Ihre gesperrten Guthaben sicherten ihnen innerhalb der Transaktion zwei Senatssitze. Zum Zeitpunkt des Angriffs hatte der Senat drei Sitze; die Kontrolle über zwei davon verschaffte dem Angreifer somit die für die Annahme eines Treasury-Vorschlags erforderliche Mehrheit.

- Schritt 3: Der Angreifer erstellte einen PancakeSwap-V3-Pool für
X/USDTund stellte dessen Liquidität bereit. Einer der kontrollierten Contracts schlug einen Treasury-Swap vor und gab dabei automatisch eine befürwortende Stimme ab; der andere gab die zweite befürwortende Stimme ab. Nachdem die Mehrheitsschwelle erreicht war, führte der Freezer Vorschlag 7 aus. Der Aufruf vonv3Swap()legte 400.000Xals Eingabemenge undamountOutMinimum = 0fest. Die Treasury erhielt nur etwa 35,68USDT. Der Trace verzeichnetvotesFor = 2undsenateSize = 3; dies zeigt, dass die erlangte Mehrheit die Operation genehmigte.

- Schritt 4: Der Angreifer zog Liquidität aus seinem neu erstellten PancakeSwap-V3-Pool ab, um die
Xder Treasury zurückzuerlangen. Einen Teil dieser Token verkaufte er über den bereits bestehenden Uniswap-V3-Pool fürX/USDTund zahlte den Flash Loan zurück. Die Rückzahlung wurde durch den anschließenden Verkauf finanziert, nicht durch eine sofortige Auszahlung der gesperrten Staking-Positionen.
Jetzt mit Phalcon Explorer starten
Transaktionen eingehend analysieren, um fundiert zu handeln
Jetzt kostenlos ausprobierenFazit
Der Vorfall war die Folge eines fehlerhaften Governance-Designs: Aktuelle gesperrte Guthaben verliehen sofort Entscheidungsbefugnis, und genehmigte Vorschläge konnten ohne Timelock ausgeführt werden. Der Angreifer nutzte beide Bedingungen, um eine Mehrheit zu erlangen und sie einzusetzen, bevor der Flash Loan zurückgezahlt werden musste. Anschließend verkaufte die Treasury 400.000 X für etwa 35,68 USDT über den vom Angreifer kontrollierten PancakeSwap-V3-Pool. Der Angreifer zog Liquidität aus diesem Pool ab, um die Token der Treasury zurückzuerlangen, verkaufte einen Teil davon über den separaten, bereits bestehenden Uniswap-V3-Pool für X/USDT und verwendete den Erlös, um den Flash Loan zurückzuzahlen und einen Gewinn zu behalten.
Die Governance sollte ein Mindestalter des Stakes verlangen oder die Sitzberechtigung und Stimmrechte anhand einer historischen Guthaben-Momentaufnahme bestimmen, die in einem Block vor der aktuellen Transaktion erstellt wurde. Dies verhindert, dass innerhalb der Transaktion finanzierte Positionen sofort Treasury-Bewegungen genehmigen können. Ein Timelock zwischen Genehmigung und Ausführung sollte verhindern, dass die gesamte Abfolge aus Übernahme und Entnahme innerhalb einer Transaktion abgeschlossen wird, und Zeit geben, einen bösartigen Vorschlag zu prüfen oder zu stornieren. Diese Kontrollmaßnahmen betreffen unterschiedliche Phasen des Governance-Ablaufs und sollten bei einem Smart-Contract-Audit gemeinsam bewertet werden.
Quellen
[1] BlockSec Phalcon: Analyse des NEM-Token-Vorfalls
[2] BlockSec Phalcon: Analyse des Governance-Vorfalls bei X100 Freezer
Kostenloser Sicherheitsscan
Eine schnelle Sicherheitsprüfung mit unserer intern entwickelten Engine für automatisierte Analysen.
Kostenlos scannenÜber BlockSec
BlockSec ist ein Full-Stack-Anbieter für Blockchain-Sicherheit und Krypto-Compliance. Wir entwickeln Produkte und Dienstleistungen, die Kunden über den gesamten Lebenszyklus von Protokollen und Plattformen hinweg dabei unterstützen, Code-Audits durchzuführen (einschließlich Smart Contracts, Blockchains und Wallets), Angriffe in Echtzeit abzuwehren, Vorfälle zu analysieren, illegale Geldflüsse nachzuverfolgen und AML/CFT-Pflichten zu erfüllen.
BlockSec hat mehrere wissenschaftliche Arbeiten zur Blockchain-Sicherheit auf renommierten Konferenzen veröffentlicht, mehrere Zero-Day-Angriffe auf DeFi-Anwendungen gemeldet, mehrere Hacks blockiert und dadurch mehr als 20 Millionen USD gerettet sowie Kryptowährungen im Milliardenwert abgesichert.
-
Offizielle Website: https://blocksec.com/
-
Offizieller Twitter-Account: https://twitter.com/BlockSecTeam



