Skip to content

Hardening: network-duty fee-bypass admits zero-fee txs from non-participants (no signer authorization at the ante layer) #1539

Open @kAIPraxisBot opened 2026-08-03 19:33 UTC 0 comments Updated 2026-08-03 19:33 UTC

Summary

NetworkDutyFeeBypassDecorator waives fees + clears min-gas-price for ~12 "network duty" message types, and the exemption is decided purely by Go message type (isExemptMessageType in inference-chain/app/ante_fee.go) — there is no check at the ante/CheckTx layer that the signer is an active participant / authorized host. So any funded account can submit structurally-valid, zero-fee duty-typed transactions. They pass CheckTx, enter the mempool, occupy block space, incur secp256k1 signature verification on every validator, and are rejected only later in DeliverTx (e.g. participant is not active).

The real authorization for these types (allowlist / participant / dedup / deadline) lives in the message handlers, which run in DeliverTx — i.e. after mempool admission and block inclusion. CheckTx runs the ante only, so unauthorized duty-typed txs are admitted regardless.

Where

  • inference-chain/app/ante_fee.goNetworkDutyFeeBypassDecorator / isExemptMessageType / GonkaFeeChecker. On main, the exempt set is 12 types: MsgSubmitPocBatch, MsgSubmitPocValidationsV2, MsgMLNodeWeightDistribution, MsgSubmitSeed, MsgSubmitHardwareDiff, MsgClaimRewards, MsgSettleDevshardEscrow, and the 5 BLS DKG types.
  • inference-chain/app/ante_poc_period.goPocPeriodValidationDecorator gates only timing (checkPocMessageTooLate) and only for the 4 PoC types; it does not check the signer. The other 8 exempt types have no ante-layer gate at all.

Impact (bounded — hardening, not a critical exploit)

An attacker imposes free, unauthenticated load: zero-fee inclusion consuming validator sig-verify + gossip + mempool + block bytes, with no economic cost (balance never drains; one-time dust to fund accounts).

Honest severity limits, verified against live mainnet consensus params (max_gas = -1, max_bytes = 22 MB): - Not a practical throughput DoS: with unlimited block gas, saturating a block is bounded only by the ~22 MB byte limit, which (given CheckTx enforces the account sequence → one pending tx per account) would require on the order of tens of thousands of concurrently-funded accounts. - The Priority: 10_000_000 boost is inert for block ordering: the app uses the default NoOpMempool, so PrepareProposal builds blocks in CometBFT FIFO order and never consults the priority. No priority-based censorship of paid traffic.

So this is a resource-abuse / free-spam hardening gap, not a network-halting exploit.

Reproduction

A zero-fee MsgClaimRewards signed by a non-participant account: CheckTx returns code 0 (admitted), the tx is included in a block, and only then fails in DeliverTx with participant is not active — having consumed block gas at zero fee.

Suggested fix

Add an ante-layer signer-authorization check for the exempt types (reject duty-typed txs from non-participants / non-allowlisted signers at CheckTx), and/or withhold the fee-bypass + priority until the signer is authorized. This mirrors the participant check that already protects MsgValidation, and closes the gap where the only authorization runs in DeliverTx after admission.


🔄 Auto-synced from Issue #1539 every hour.