CVE-2026-54754
github.com/klever-io/klever-go: Integer Underflow (Wrap or Wraparound) (CVE-2026-54754)
Beschreibung
Zusammenfassung
Wenn ein Marktplatz-Auftrag abgewickelt wird (MarketBuy / BuyItNow, und Auktion Claim), wird der Kaufpreis des Käufers in drei Teile aufgeteilt — Empfehlungsprovision, Royalties und den Restbetrag für den Verkäufer (Marktplatz-Auftragseigentümer):
marketOwnerAmount = CurrentBid − referralAmount − royaltiesAmount
Die Empfehlungsprovision und die Royalties werden unbedingt ausgezahlt, aber der Restbetrag für den Verkäufer wird nur dann ausgezahlt, wenn er positiv ist (computeMarketOwnerAmount gibt Ok zurück und zahlt nichts aus, wenn der Betrag <= 0 ist). Wenn die Summe von referral% + royalty% mehr als 100 % des Gebots beträgt, wird der marketOwnerAmount negativ und wird stillschweigend übersprungen — so dass der Marktplatz mehr KLV / Verkaufswährung auszahlt, als der Käufer bezahlt hat, indem er den Unterschied aus dem Nichts erschafft.
Die kombinierte Obergrenze royalty% + referral% <= 100% wird einmal überprüft, zur Zeit der Auflistung (Sell). Aber die beiden Prozentsätze werden asymmetrisch bei der Abwicklung bezogen:
- Der Empfehlungsprozentsatz wird in den Auftrag abgebildet bei
Sell(MarketOrderData.ReferralPercentage); - Der Royalty-Prozentsatz wird nie abgebildet — er wird live aus dem Asset zur Zeit des Kaufs gelesen
(
asset.Royalties.MarketPercentage).
Daher ist die Invariante zur Auflistungszeit nur eine Garantie für Zeit der Überprüfung/Zeit der Verwendung. Nach einer gültigen Auflistung kann der Asset-Eigentümer den Royalty MarketPercentage über AssetTrigger → UpdateRoyalties erhöhen; beim nächsten Kauf überschreiten die live Royalty und die abgebildete Empfehlung 100 %, und die Abwicklung erschafft den Überschuss. Die erschaffenen Mittel landen in von Angreifern kontrollierten Empfehlungs-/Royalty-Adressen.
Dies wurde aktiv auf der Hauptnetzwerk ausgenutzt (siehe Beweise), indem mehrere Millionen KLV vor dem Einsatz des Notfall-Schutzes erschaffen wurden.
Betroffenes Komponente
- Repository:
klever-io/klever-go(Knoten). - Abwicklung / Erschaffungsort:
core/kapp/market/market.go—executeBuyMarket(L575+),computeReferralAmount(L361+),computeRoyaltiesAmount(L490+),computeRoyaltiesFixedDeposit(L443+),computeMarketOwnerAmount(L540+). - TOCTOU-Quellen: Kombinierte Überprüfung bei
Sell(market.go:908), Abbildung des Auftrags für Empfehlung, aber nicht Royalty (market.go:997), live Mutation der Royalty übercore/kapp/kda/trigger.go—handleUpdateRoyaltiesNFTandSFT(L613+, setztasset.Royalties.MarketPercentagebei L670). - Erreichbar von sowohl
Buy(BuyItNow,market.go:204+) als auch AuktionClaim(market.go:705,market.go:731). - Vor dem Fix: nicht durch irgendeine Fork-Fahne gesperrt — auf der Hauptnetzwerk ausnutzbar. Der Fix ist hinter der neuen
FixMarketBuyOverflowAktivierungs-Epoche Fahne gesperrt.
Ursache
1. Abwicklung zahlt Empfehlung + Royalty unbedingt, Restbetrag für Verkäufer nur wenn positiv
core/kapp/market/market.go — executeBuyMarket (L575+):
referralAmount, _ := tools.ComputePercentageI64(marketOrder.CurrentBid,
int64(marketOrder.ReferralPercentage), ...) // L583: SNAPSHOT Empfehlung %
royaltiesAmount, _ := tools.ComputePercentageI64(marketOrder.CurrentBid,
int64(asset.Royalties.MarketPercentage), ...) // L587: LIVE Royalty %
marketOwnerAmount := marketOrder.CurrentBid - referralAmount - royaltiesAmount // L591: kann negativ werden
// ---- FIX (FixMarketBuyOverflow), hinzugefügt durch das Patch ----
if m.forkController.FixMarketBuyOverflow() && marketOwnerAmount < 0 { // L593-596
ctx.Receipts().AddError(ctx.ContractID(), common.ErrFieldInvalidRoyalties, common.ErrInvalidValue.Error())
return transaction.Transaction_AmountInvalid, common.ErrInvalidValue
}
m.computeReferralAmount(ctx, marketOrder, referralAmount, currencyID) // zahlt Empfehlung vollständig aus
m.computeRoyaltiesFixedDeposit(ctx, marketOrder, asset) // zahlt feste Royalty (KLV) aus
m.computeRoyaltiesAmount(ctx, marketOrder, asset, currencyID, royaltiesAmount) // zahlt % Royalty vollständig aus
m.computeMarketOwnerAmount(ctx, marketOrder, currencyID, marketOwnerAmount) // <-- überspringt wenn <= 0
computeMarketOwnerAmount (L540-542) — der stille Übergang:
func (m *marketKapp) computeMarketOwnerAmount(... marketOwnerAmount int64) (... , error) {
if marketOwnerAmount <= 0 {
return transaction.Transaction_Ok, nil // negativer Anteil des Verkäufers verworfen, KEIN Fehler
}
// ... AddToBalance(marketOwnerAmount) ...
}
Während computeReferralAmount (L376) und computeRoyaltiesAmount (L515) jeweils AddToBalance(...) den vollständig berechneten Betrag mit keinem entsprechenden Debit vom Käufer jenseits des einzigen
bidderAcc.SubFromBalance(amount) in Buy (market.go:301) hinzufügen.
Konservierung bricht: Käufer wird einmal mit bid belastet; Empfänger werden mit
referralAmount + royaltiesAmount gutgeschrieben. Wenn diese Summe > bid ist, wird der Überschuss
(referralAmount + royaltiesAmount − bid) erschaffen.
2. Die kombinierte ≤100% Invariante wird nur zur Auflistungszeit durchgesetzt
Sell (market.go:908) lehnt korrekt eine Auflistung ab, deren kombinierter Anteil mehr als 100 % beträgt:
if asset.Royalties.MarketPercentage + marketplace.ReferralPercentage > core.HundredPercent {
return transaction.Transaction_ParameterInvalid, common.ErrInvalidValue
}
…und bildet Empfehlung in den Auftrag ab, aber nicht Royalty (market.go:997-998):
marketOrder := &kapps.MarketOrderData{
// ...
ReferralPercentage: marketplace.ReferralPercentage, // abgebildet
RoyaltiesFixedDeposit: asset.Royalties.MarketFixed, // abgebildet
// HINWEIS: asset.Royalties.MarketPercentage wird NICHT abgebildet -> live bei Kauf gelesen
}
MarketOrderData hat kein Feld für den Royalty-Prozentsatz (kapps/market.pb.go), daher liest die Abwicklung ihn immer live aus dem (veränderlichen) Asset.
3. Royalty % ist nach der Auflistung veränderbar
core/kapp/kda/trigger.go — handleUpdateRoyaltiesNFTandSFT (L613+) erlaubt es dem Asset-Eigentümer, asset.Royalties.MarketPercentage (L670) mit nur einer pro-Feld <= 100% Überprüfung (CheckValid100Params,
L651) zu überschreiben — es hat keine Kenntnis von irgendeinem snapshotted Empfehlungsanteil eines bestehenden Marktplatz-Auftrags. So kann der Eigentümer die Royalty für das Asset auf 100 % erhöhen (`AssetTrigger / UpdateRoyal
Beweise
Praktische Ausnutzung
- Erstellen Sie ein neues Asset mit einem anfänglichen Royalty-Prozentsatz von 0.
- Richten Sie einen Marktplatz ein, der eine Empfehlungsprovision von 10000 (was 100 % entspricht) hat.
- **Listen
Metriken
Weakness-Klassen (CWE)
CWE-191Base
Integer Underflow (Wrap or Wraparound)
The product subtracts one value from another, such that the result is less than the minimum allowable integer value, which produces a value that is not equal to the correct result.
cwe.mitre.org →CWE-367Base
Time-of-check Time-of-use (TOCTOU) Race Condition
The product checks the state of a resource before using that resource, but the resource's state can change between the check and the use in a way that invalidates the results of the check.
cwe.mitre.org →CWE-682Pillar
Incorrect Calculation
The product performs a calculation that generates incorrect or unintended results that are later used in security-critical decisions or resource management.
cwe.mitre.org →
Betroffene Produkte
Aus der Hersteller-/CERT-Meldung extrahierte Produkte und Versionsbereiche. Ein Version-Range wie „<4.14.6“ impliziert die Update-Empfehlung „auf 4.14.6 oder höher aktualisieren“.
go
github.com/klever-io/klever-go
Quellen & Referenzen
- https://github.com/klever-io/klever-go/security/advisories/GHSA-p7gw-2pcp-5pf8x_refsource_CONFIRM
- https://github.com/klever-io/klever-go/commit/8bcc600b0ac88070740c63c7ce1c8a968dd85251x_refsource_MISC
- https://github.com/klever-io/klever-go/releases/tag/v1.7.19x_refsource_MISC
- https://github.com/klever-io/klever-gopackage