Fix mutable tx handle and memo ID validation gap#939
Fix mutable tx handle and memo ID validation gap#939
Conversation
Return a defensive XDR copy from TransactionBase#tx getter to prevent mutation of the internal XDR object after construction, closing a split-brain where displayed fields could diverge from signed bytes. Internal methods now use this._tx directly for signing/serialization. Add regex validation in Memo._validateIdValue to reject non-plain-decimal strings (e.g. "1e18", "1.0") that pass BigNumber checks but crash BigInt() at XDR serialization time. Fixes #160 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Size Change: -4.26 kB (-0.12%) Total Size: 3.53 MB
|
There was a problem hiding this comment.
Pull request overview
This PR hardens transaction and memo handling by preventing external mutation of internal XDR objects and by tightening memo ID input validation to avoid problematic numeric formats.
Changes:
- Make
TransactionBase.txreturn a defensive XDR copy instead of the internal_txreference. - Update
TransactionandFeeBumpTransactioninternals to use_txdirectly (avoids cloning overhead in signing/serialization paths). - Strengthen
MemoID validation by rejecting non-digit-only strings (e.g., scientific notation / decimals).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/transaction_base.js | Returns a defensive copy from tx getter to prevent post-construction XDR mutation. |
| src/transaction.js | Switches internal accesses from this.tx to this._tx to avoid defensive-copy overhead. |
| src/fee_bump_transaction.js | Switches internal accesses from this.tx to this._tx to avoid defensive-copy overhead. |
| src/memo.js | Tightens memo ID validation to only allow plain decimal digits before BigNumber parsing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| get tx() { | ||
| return this._tx; | ||
| // Return a defensive copy to prevent mutation of the internal XDR object | ||
| // after construction. Signing and serialization use this._tx directly, | ||
| // so exposing the live reference could let callers alter signed bytes | ||
| // without changing the cached display fields (fee, source, memo, etc.). | ||
| return this._tx.constructor.fromXDR(this._tx.toXDR()); | ||
| } |
| // Reject anything that isn't plain decimal digits (no scientific notation, | ||
| // no decimals, no signs). BigNumber accepts formats like "1e18" and "1.0" | ||
| // which pass numeric checks but crash BigInt()/UnsignedHyper.fromString(). | ||
| if (!/^\d+$/.test(value)) { | ||
| throw error; | ||
| } |
…ng decimal zero (#940) * Initial plan * Add negative test cases for memo ID scientific notation and trailing decimal zero Co-authored-by: sagpatil <1414227+sagpatil@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: sagpatil <1414227+sagpatil@users.noreply.github.com>
* Initial plan * Add unit test for tx getter defensive copy behavior Co-authored-by: sagpatil <1414227+sagpatil@users.noreply.github.com> * Rename variable t to txCopy for clarity in tx getter test Co-authored-by: sagpatil <1414227+sagpatil@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: sagpatil <1414227+sagpatil@users.noreply.github.com>
|
I have a concern with this approach in that it's a silent change to the previous functionality. We would need to note this as a breaking change for users who are mutating the underlying |
Return a defensive XDR copy from TransactionBase#tx getter to prevent mutation of the internal XDR object after construction, closing a split-brain where displayed fields could diverge from signed bytes. Internal methods now use this._tx directly for signing/serialization.
Add regex validation in Memo._validateIdValue to reject non-plain-decimal strings (e.g. "1e18", "1.0") that pass BigNumber checks but crash BigInt() at XDR serialization time.
Fixes (https://github.com/stellar/internal-agents/issues/160)