Security releases Review: Bor v2.10.0 (Austin HF) and Heimdall v0.11.0 (Kyoto HF)

Summary

Over the last few weeks we shipped two coordinated hardforks across the
Polygon PoS clients: Austin HF on Bor (v2.10.0) and Kyoto HF on
Heimdall (v0.11.0). Both address security and liveness issues. As is
standard practice for consensus-affecting fixes, they were first rolled out
privately and validated on Amoy before mainnet activation, and made public
once the fleet was safe.

This post summarizes what each hardfork fixed, what the impact could have
been, and what node operators need to do. Both hardforks are already active
on Amoy and mainnet — if you haven’t upgraded past the activation heights
below, your node has already forked off canonical and needs to catch up.


Bor v2.10.0 — Austin hardfork

Two changes, both closing denial-of-service paths in block processing.

  • Per-block state-sync gas bound. State-sync events (L1→L2 bridge
    deposits) execute contract code and precompiles just like ordinary
    transactions, but the gas they consume wasn’t metered against a hard cap.
    A block carrying enough state-sync events, or one especially expensive
    event, could make block processing take long enough to transiently stall
    the chain. Austin adds an explicit per-block bound on state-sync gas,
    matching the treatment normal transaction gas already gets.

  • Removal of the TxDependency wire field. Bor used this block
    extra-data field as a hint for parallel execution — which transactions in
    a block don’t conflict with each other. It carried no size limit, so a
    block producer could include an arbitrarily large TxDependency blob in
    an otherwise valid sibling block, and any peer receiving it would crash
    trying to process it. Austin removes the field from the wire format
    entirely; parallel execution doesn’t depend on peers trusting a
    producer’s hint to work correctly, so nothing downstream is affected.

Activation:

  • Amoy: block 44,120,000
  • Mainnet: block 91,949,700

Impact if unfixed: both were resource-exhaustion / denial-of-service
vectors against block processing, not consensus-correctness issues. Neither
was observed causing disruption on mainnet — they were addressed
proactively ahead of any exploitation.


Heimdall v0.11.0 — Kyoto hardfork

Kyoto bundles a set of consensus-hardening and input-validation fixes
across ABCI, milestone, bor, stake, topup, clerk, and bridge processing.

  • Bound on nested google.protobuf.Any depth in transactions. Heimdall
    transactions wrap their inner messages in Any types, and Any can nest
    inside Any. Without a cap, a single crafted transaction with deeply
    nested Any fields could force every validator to do a large amount of
    decode work at once — cheap for the sender to construct, expensive for
    the whole network to process. Kyoto adds a byte-level pre-scan that
    rejects a transaction once its nesting passes a threshold, enforced
    identically at mempool admission (CheckTx) and on the consensus path
    (ProcessProposal), so the same transaction can’t be admitted on one
    path and rejected on another. The threshold sits above anything a
    legitimate transaction would ever produce.

  • Fee-coin count cap. A transaction could previously declare an
    unbounded list of fee coins, and the validation scan over that list was
    O(n). Kyoto caps the count before the scan runs.

  • Checkpoint signature recovery-byte normalization. A checkpoint
    signature’s recovery byte wasn’t canonicalized before L1 submission, so a
    validly-signed checkpoint could be submitted in a form that fails
    signature recovery on L1 — stalling checkpoint anchoring without forging
    anything.

  • Idempotent producer-downtime handling. Processing the same downtime
    message twice used to create a second span each time; it’s now a no-op
    on repeat.

  • Milestone range voting bound to the signed parent hash. A
    validator’s vote could previously count toward a milestone range
    extension without having attested to the specific parent it extended
    from.

  • Checkpoint-window continuity check before the Bor RPC call in
    vote-extension validation, closing a gap where a discontinuous checkpoint
    window could reach that call in an unexpected state.

  • Non-halting future-span creation. A failed future-span creation no
    longer blocks milestone commit — it degrades and retries at the next
    boundary instead.

  • Injective L1-event replay keys for topup, clerk, and stake, for
    out-of-range log indexes — closes a narrow case where two distinct L1
    events could hash to the same replay key and one would silently shadow
    the other.

All Kyoto-gated behavior is inert below the fork height; the guards only
fire on the crafted inputs they’re designed to catch, and normal traffic is
unaffected.

Activation:

  • Amoy: height 42,252,000
  • Mainnet: height 51,533,000

Impact if unfixed: the nested-Any decode bound closes the most
severe issue in this batch — a permissionless way to force costly, correlated
work across the whole validator set. The remaining items harden checkpoint
finality, milestone accounting, and L1-event replay against edge cases and
resource pressure. All were resolved and validated before either hardfork
activated.


What to upgrade

Release Who needs it Urgency
Bor v2.10.0 (Austin) All nodes Mandatory — already active on Amoy and mainnet
Heimdall v0.11.0 (Kyoto) All validators and full nodes Mandatory — already active on Amoy and mainnet

Both are plain binary upgrades — no state migration, no genesis change, no
resync required. If your node is on an earlier version past the activation
heights above, it has already fallen out of consensus; upgrading and rolling back
to pre-HFs heights lets it resync and rejoin.