Hi Push Chain team — reporting two issues found via manual source review of push-chain-node (x/uexecutor). Both reproducible from the code; no mainnet exploitation done. Posting publicly since no security contact / private advisory is enabled on the repo.
1) Quorum off-by-one (bridge liveness halt)
File: x/uexecutor/keeper/voting.go:33 (and :97 outbound)
votesNeeded := (VotesThresholdNumeratortotalValidators)/VotesThresholdDenominator + 1
With Numerator=2, Denominator=3, correct >2/3 quorum = ceil(2N/3), but code = floor(2N/3)+1.
When eligible validator count N is a multiple of 3 (3,6,9,12...), required votes = 100%.
One offline validator then blocks ALL inbound/outbound finalization -> bridge halt.
Fix: votesNeeded := (totalValidatorsVotesThresholdNumerator + VotesThresholdDenominator - 1) / VotesThresholdDenominator (drop the +1). Add test for N=1..200.
2) Gas overcharge ignores MaxFeePerGas
File: x/uexecutor/keeper/fees.go CalculateGasCost (47-91)
lines 69-77 (EIP-1559 cap) are commented out -> effectiveGasPrice = baseFee only.
DeductGasFeesFromReceipt (line 137) burns baseFeegasUsed with no MaxFeePerGas check.
Since baseFee is validator-controlled, raising it overcharges users far above their signed cap.
Fix: re-enable effectiveGasPrice = min(baseFee+maxPriorityFeePerGas, maxFeePerGas); clamp gasCost to MaxFeePerGasgasUsed in DeductGasFeesFromReceipt.
Happy to provide full PoC / clarify. Please advise on coordinated fix + disclosure. Thanks!
Hi Push Chain team — reporting two issues found via manual source review of push-chain-node (x/uexecutor). Both reproducible from the code; no mainnet exploitation done. Posting publicly since no security contact / private advisory is enabled on the repo.
1) Quorum off-by-one (bridge liveness halt)
File: x/uexecutor/keeper/voting.go:33 (and :97 outbound)
votesNeeded := (VotesThresholdNumeratortotalValidators)/VotesThresholdDenominator + 1
With Numerator=2, Denominator=3, correct >2/3 quorum = ceil(2N/3), but code = floor(2N/3)+1.
When eligible validator count N is a multiple of 3 (3,6,9,12...), required votes = 100%.
One offline validator then blocks ALL inbound/outbound finalization -> bridge halt.
Fix: votesNeeded := (totalValidatorsVotesThresholdNumerator + VotesThresholdDenominator - 1) / VotesThresholdDenominator (drop the +1). Add test for N=1..200.
2) Gas overcharge ignores MaxFeePerGas
File: x/uexecutor/keeper/fees.go CalculateGasCost (47-91)
lines 69-77 (EIP-1559 cap) are commented out -> effectiveGasPrice = baseFee only.
DeductGasFeesFromReceipt (line 137) burns baseFeegasUsed with no MaxFeePerGas check.
Since baseFee is validator-controlled, raising it overcharges users far above their signed cap.
Fix: re-enable effectiveGasPrice = min(baseFee+maxPriorityFeePerGas, maxFeePerGas); clamp gasCost to MaxFeePerGasgasUsed in DeductGasFeesFromReceipt.
Happy to provide full PoC / clarify. Please advise on coordinated fix + disclosure. Thanks!