Skip to content

fix: reject non-finite bridge lock amounts#5465

Merged
Scottcjn merged 1 commit into
Scottcjn:mainfrom
ramimbo:fix-bridge-lock-nan-5361
May 18, 2026
Merged

fix: reject non-finite bridge lock amounts#5465
Scottcjn merged 1 commit into
Scottcjn:mainfrom
ramimbo:fix-bridge-lock-nan-5361

Conversation

@ramimbo
Copy link
Copy Markdown
Contributor

@ramimbo ramimbo commented May 16, 2026

What Changed

  • Reject non-finite /bridge/lock amounts (NaN, Infinity, -Infinity) immediately after parsing.
  • Add regression coverage proving those payloads return 400 with the existing invalid amount response instead of reaching base-unit conversion or min/max checks.

Why

float("NaN") bypasses normal min/max comparisons and then raises during int(round(...)), producing an unhandled error path. Non-finite values should be treated the same as other invalid amounts before any lock state or proof handling runs.

Fixes #5361

Testing / Evidence

  • python -m pytest bridge/test_bridge_api.py::TestLockEndpoint::test_lock_rejects_non_finite_amount -q -> 3 passed
  • python -m pytest bridge/test_bridge_api.py -q -> 44 passed
  • python -m py_compile bridge/bridge_api.py bridge/test_bridge_api.py -> passed
  • git diff --check -- bridge/bridge_api.py bridge/test_bridge_api.py -> passed

BCOS Checklist

  • Add a tier label: BCOS-L1 or BCOS-L2 (this bridge validation change should be BCOS-L2)
  • If adding new code files, include SPDX header near the top (no new code files added)
  • Provide test evidence

RTC payout address for any accepted bounty: RTC877021895fd29d034f35c87e1b37af8534703792

@github-actions
Copy link
Copy Markdown
Contributor

Welcome to RustChain! Thanks for your first pull request.

Before we review, please make sure:

  • Non-doc PRs have a BCOS-L1 or BCOS-L2 label
  • Doc-only PRs are exempt from BCOS tier labels when they only touch docs/**, *.md, or common image/PDF files
  • New code files include an SPDX license header
  • You've tested your changes against the live node

Bounty tiers: Micro (1-10 RTC) | Standard (20-50) | Major (75-100) | Critical (100-150)

A maintainer will review your PR soon. Thanks for contributing!

@github-actions github-actions Bot added BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) size/S PR: 11-50 lines labels May 16, 2026
@ramimbo
Copy link
Copy Markdown
Contributor Author

ramimbo commented May 16, 2026

CI note: the CI / test job currently fails during repository-wide test collection before it reaches the bridge tests or this change. The log shows missing CI dependencies (aiohttp, flask_cors, matplotlib), which matches the current upstream baseline failure pattern.

Focused validation for this PR remains:

  • python -m pytest bridge/test_bridge_api.py -q -> 44 passed
  • python -m py_compile bridge/bridge_api.py bridge/test_bridge_api.py -> passed
  • git diff --check -- bridge/bridge_api.py bridge/test_bridge_api.py -> passed

Copy link
Copy Markdown
Contributor

@HCIE2054 HCIE2054 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Copy Markdown
Contributor

@kekehanshujun kekehanshujun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The fix rejects NaN, Infinity, and -Infinity immediately after parsing and before any range checks or base-unit conversion, which matches #5361's expected behavior and keeps the response consistent with other invalid amounts.

Validation run on the PR diff:

  • python -m py_compile bridge/bridge_api.py bridge/test_bridge_api.py
  • python -m pytest bridge/test_bridge_api.py::TestLockEndpoint::test_lock_rejects_non_finite_amount -q --tb=short -> 3 passed
  • python -m pytest bridge/test_bridge_api.py -q --tb=short -> 44 passed
  • git diff --check -- bridge/bridge_api.py bridge/test_bridge_api.py

Copy link
Copy Markdown
Contributor

@galanime galanime left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the non-finite bridge amount guard. The patch is small and matches #5361's failure mode: NaN/Infinity are rejected immediately after float(...) parsing, before min/max comparison and before _amount_to_base(...) can raise.

Validation run on head ce7d1e80e55efb0f8b7e13afcdd6d9dc5ab4a5cc:

  • python -m pytest bridge\test_bridge_api.py::TestLockEndpoint::test_lock_rejects_non_finite_amount -q -o addopts='' -> 3 passed after creating the local Windows \tmp directory required by the existing test fixture.
  • python -m py_compile bridge\bridge_api.py bridge\test_bridge_api.py -> passed.
  • git diff --check origin/main...HEAD -> passed.

One environment note: the full bridge\test_bridge_api.py file is still not reliably Windows-portable because it hard-codes /tmp/bridge_test_727.db and can hit sqlite3.OperationalError or a Windows file-lock PermissionError during collection. That appears to be pre-existing test harness behavior rather than a regression from this PR, and the focused non-finite amount regression passes once the fixture path exists.

Copy link
Copy Markdown

@ZacharyZhang-NY ZacharyZhang-NY left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed PR #5465 at ce7d1e8.

Validation performed on Windows Python 3.12:

  • python -m py_compile bridge/bridge_api.py bridge/test_bridge_api.py passed.
  • Created C:\tmp because the test module uses /tmp/bridge_test_727.db and Windows maps that path to C:\tmp\....
  • python -m pytest bridge/test_bridge_api.py::TestLockEndpoint::test_lock_rejects_non_finite_amount -q passed with 3 passed in 0.15s.
  • python -m pytest bridge/test_bridge_api.py -q passed with 44 passed in 0.29s.

The fix is placed immediately after float parsing and before sender/min/max/base-unit handling, so NaN, Infinity, and -Infinity share the existing invalid amount 400 response and avoid the previous conversion path. I did not find a blocking issue.

Copy link
Copy Markdown
Contributor

@HCIE2054 HCIE2054 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Copy Markdown
Contributor

@HCIE2054 HCIE2054 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Copy Markdown
Contributor

@HCIE2054 HCIE2054 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Copy Markdown
Contributor

@HCIE2054 HCIE2054 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Copy Markdown
Contributor

@HCIE2054 HCIE2054 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Copy Markdown

@ZacharyZhang-NY ZacharyZhang-NY left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed PR #5465 at head ce7d1e8.

Validation performed:

  • Checked issue #5361. The scoped bug is /bridge/lock accepting non-finite parsed amounts such as NaN through range checks and reaching base-unit conversion, which raises instead of returning a clean client error.
  • git fetch origin pull/5465/head:review-pr-5465 --force
  • git diff --check origin/main...review-pr-5465 -- bridge/bridge_api.py bridge/test_bridge_api.py -> passed.
  • python -m py_compile bridge/bridge_api.py bridge/test_bridge_api.py on an extracted PR-head tree -> passed.
  • python -m pytest bridge/test_bridge_api.py::TestLockEndpoint::test_lock_rejects_non_finite_amount -q --confcutdir= -> 3 passed.
  • python -m pytest bridge/test_bridge_api.py -q --confcutdir= -> 44 passed.
  • Ran Flask test-client probes for NaN, Infinity, and -Infinity; each returned 400 with {"error":"invalid amount"}.

The bridge lock endpoint now rejects non-finite amounts immediately after parsing and before range checks or base-unit conversion. Approving.

Copy link
Copy Markdown

@TJCurnutte TJCurnutte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — focused bridge lock validation pass.

Validation:

  • git diff --check origin/main...HEAD -- bridge/bridge_api.py bridge/test_bridge_api.py
  • python3 -B -m py_compile bridge/bridge_api.py bridge/test_bridge_api.py
  • uv run --no-project --with pytest --with flask python -B -m pytest -q bridge/test_bridge_api.py --noconftest44 passed in 0.34s
  • Flask test-client probe with BRIDGE_REQUIRE_PROOF=false verified /bridge/lock returns HTTP 400 {"error":"invalid amount"} for "NaN", "Infinity", and "-Infinity", while finite "1.25" still returns 201 with state requested.

Reasoning:
float() accepts these non-finite strings, so the added math.isfinite(amount_float) gate is in the right place before min/max checks and DB persistence. The regression test covers all three non-finite spellings, and the full bridge API test file still passes.

@BossChaos
Copy link
Copy Markdown
Contributor

Code Review — Bounty #73

PR: fix: reject non-finite bridge lock amounts by @ramimbo
Files changed: 2 (+16/-0)

  • ✅ Bug fix or input validation
  • 🔒 Auth/authz code reviewed
  • ✅ Input validation present
  • ✅ Error handling present

Summary

This is a bug fix PR. Changes appear consistent with project patterns.

Wallet: 0xdaE5d307339074A24F579dB48e7c639359D94904

Reviewing under Bounty #73 — Code Review Bounty Program

Copy link
Copy Markdown
Contributor

@HCIE2054 HCIE2054 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Copy Markdown
Contributor

@HCIE2054 HCIE2054 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Copy Markdown
Contributor

@HCIE2054 HCIE2054 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Copy Markdown
Contributor

@508704820 508704820 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reject non-finite bridge lock amounts. Verify: (1) NaN, Infinity, -Infinity are all rejected. (2) Rejection happens at the API boundary, not deep in bridge logic. (3) Zero and negative amounts also rejected for lock operations. - Xeophon (security review)

Copy link
Copy Markdown
Contributor

@HCIE2054 HCIE2054 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Copy Markdown
Contributor

@HCIE2054 HCIE2054 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@508704820
Copy link
Copy Markdown
Contributor

Security Review ✅ IMPORTANT

Reject NaN/Infinity/-Infinity bridge lock amounts. This is a classic float exploitation: float('NaN') bypasses all min/max comparisons (NaN < X is always False, NaN > X is always False) and then crashes at int(round(...)). Attacker could use this to bypass amount validation or cause 500 errors.

Reviewed by Xeophon - Solana: Lt9nERv6VHsojw15LpFeiaabuphAggzfLF9sM9UXRrZ

Copy link
Copy Markdown
Contributor

@HCIE2054 HCIE2054 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Copy Markdown
Contributor

@HCIE2054 HCIE2054 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@Scottcjn Scottcjn merged commit ce861df into Scottcjn:main May 18, 2026
11 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) size/S PR: 11-50 lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Bridge lock NaN amount bypasses range validation and raises during conversion

9 participants