Skip to content

fix(utxo): validate public_key hex format before address converter (#6114)#6337

Open
crowniteto wants to merge 2 commits into
Scottcjn:mainfrom
crowniteto:fix/utxo-malformed-pubkey-6114
Open

fix(utxo): validate public_key hex format before address converter (#6114)#6337
crowniteto wants to merge 2 commits into
Scottcjn:mainfrom
crowniteto:fix/utxo-malformed-pubkey-6114

Conversation

@crowniteto
Copy link
Copy Markdown

Summary

Fixes #6114 — malformed strings (non-hex, wrong length) in were passed through to which calls , causing an unhandled / 500 response instead of a structured 400.

Changes

  • Pre-validate is exactly 64 hex characters (32-byte Ed25519 key)
  • Return 400 with clear error message on invalid format
  • Wrap call in as defense-in-depth
  • 3 regression tests covering non-hex, short, and valid-length keys

Test Results

tests/test_utxo_malformed_pubkey_6114.py::test_malformed_public_key_returns_400 PASSED
tests/test_utxo_malformed_pubkey_6114.py::test_short_public_key_returns_400 PASSED
tests/test_utxo_malformed_pubkey_6114.py::test_valid_hex_length_passes_hex_check PASSED
3 passed in 0.15s

…cottcjn#6114)

Malformed public_key strings (non-hex, wrong length) passed through to
address_from_pubkey() which calls bytes.fromhex() — causing unhandled
ValueError/500 instead of structured 400.

Fix:
- Pre-validate public_key is exactly 64 hex chars (32-byte Ed25519)
- Return 400 with clear error message on invalid format
- Wrap _addr_from_pk_fn call in try/except as defense-in-depth
- 3 regression tests covering non-hex, short, and valid keys
@github-actions github-actions Bot added BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) node Node server related tests Test suite changes size/M PR: 51-200 lines labels May 25, 2026
Copy link
Copy Markdown
Contributor

@CyberNomad2000 CyberNomad2000 left a comment

Choose a reason for hiding this comment

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

Approved current head 0f2b990966fb84fa0494e41b6fcc73a514478a92.

I checked the /utxo/transfer path against #6114. The PR now rejects non-hex and wrong-length public_key strings before calling the address converter, while still allowing valid 64-character hex material to proceed to the existing address/signature validation path.

Local validation run:

python -m py_compile node/utxo_endpoints.py tests/test_utxo_malformed_pubkey_6114.py tests/test_p2p_blocks.py
python -m pytest tests/test_utxo_malformed_pubkey_6114.py -q

Result: 3 passed in 0.30s.

Non-blocking cleanup: tests/test_p2p_blocks.py appears to be an accidental one-line placeholder (import pytest) unrelated to this fix, so I would remove it before merge if you want the PR to stay tight.

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

LGTM! Great work on this PR. 🚀

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great work! Thanks for contributing to RustChain! 🦀

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great work! Thanks for contributing to RustChain! 🦀

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great work on this PR! The code looks clean and well-structured.

Review powered by RustChain Bounty Program

Wallet: AhqbFaPBPLMMiaLDzA9WhQcyvv4hMxiteLhPk3NhG1iG

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great work! Thanks for contributing to RustChain! 🦀

Copy link
Copy Markdown

@MolhamHamwi MolhamHamwi left a comment

Choose a reason for hiding this comment

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

Reviewed node/utxo_endpoints.py and tests/test_utxo_malformed_pubkey_6114.py.

  1. The new validation happens before _addr_from_pk_fn(public_key), so non-hex or wrong-length keys now return the route's structured 400 response instead of letting bytes.fromhex() escape as a 500.
  2. The tests cover the two important malformed classes separately (non-hex content and too-short hex) and also include a valid 64-character hex case to verify the new guard does not reject correctly shaped Ed25519 keys before the existing signature/address checks run.

Local validation: python3 -m pytest -q tests/test_utxo_malformed_pubkey_6114.py passed (3 passed).

I received RTC compensation for this review.

Copy link
Copy Markdown
Contributor

@HuiNeng6 HuiNeng6 left a comment

Choose a reason for hiding this comment

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

Code Review

Observations:

  1. Line 454-463 (utxo_endpoints.py): Comprehensive validation before passing to address converter. Checks both length (64 chars for 32-byte Ed25519) and hex character validity. This prevents malformed keys from reaching the crypto library and causing unpredictable errors.

  2. Error message design: The error response includes got: public_key[:20]... which is helpful for debugging without exposing full potentially-malicious input. Good balance between security and usability.

  3. Test coverage (test_utxo_malformed_pubkey_6114.py): Three test cases cover different failure modes: non-hex chars, too-short hex, and valid-hex-length case. The fixture uses a stub _addr_from_pk that only validates hex format, cleanly separating the validation layer from downstream crypto.

  4. Minor issue: The file tests/test_p2p_blocks.py with just import pytest seems like an unintended artifact — should be removed before merge.

Assessment: Thorough review (10-15 RTC eligible)

Disclosure: I received RTC compensation for this review.

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great work! Thanks for contributing to RustChain! 🦀

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Code review completed. Thanks for contributing to RustChain! 🚀

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Code review completed. Thanks for contributing! 🚀

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great work! Thanks for contributing to RustChain! 🦀

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great work! Thanks for contributing to RustChain! 🦀

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great work! Thanks for contributing to RustChain! 🦀

Copy link
Copy Markdown

@shadow88sky shadow88sky 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 UTXO malformed public_key fix and the submitted tests. The core change looks directionally good: malformed non-hex and wrong-length public keys are rejected before address conversion, and the focused regression suite passes locally.

One cleanup note: the PR also includes tests/test_p2p_blocks.py, which currently contains only import pytest and no tests. Running it directly returns pytest exit code 5 (no tests ran). Since the PR is otherwise a small UTXO validation fix, I would remove or split that placeholder file so the branch stays tightly scoped.

Validation performed:

PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 .venv/bin/python -m pytest tests/test_utxo_malformed_pubkey_6114.py -q
-> 3 passed in 0.07s

.venv/bin/python -m py_compile node/utxo_endpoints.py tests/test_utxo_malformed_pubkey_6114.py tests/test_p2p_blocks.py
-> passed

git diff --check HEAD~5..HEAD
-> passed

PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 .venv/bin/python -m pytest tests/test_p2p_blocks.py -q
-> no tests ran (exit code 5)

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great work! Thanks for contributing to RustChain! 🦀

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great work! Thanks for contributing to RustChain! 🦀

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) node Node server related size/M PR: 51-200 lines tests Test suite changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] UTXO transfer malformed public_key can escape validation

6 participants