fix(api): harden external input validation - #21
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
1 issue found across 15 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="framework/src/test/java/org/tron/core/services/interfaceOnSolidity/http/RewardBrokerageAddressValidationTest.java">
<violation number="1" location="framework/src/test/java/org/tron/core/services/interfaceOnSolidity/http/RewardBrokerageAddressValidationTest.java:42">
P3: The Solidity and PBFT test files duplicate the entire harness (reflection-backed wallet factory, request builder, inject helper, and the reward/brokerage rejection test) differing only in the wallet type and injected field name. Extract a shared base class or parameterized harness to avoid maintaining the same assertions in two places.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| } | ||
|
|
||
| @Test | ||
| public void rewardAndBrokerageMirrorsRejectMalformedAddresses() throws Exception { |
There was a problem hiding this comment.
P3: The Solidity and PBFT test files duplicate the entire harness (reflection-backed wallet factory, request builder, inject helper, and the reward/brokerage rejection test) differing only in the wallet type and injected field name. Extract a shared base class or parameterized harness to avoid maintaining the same assertions in two places.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At framework/src/test/java/org/tron/core/services/interfaceOnSolidity/http/RewardBrokerageAddressValidationTest.java, line 42:
<comment>The Solidity and PBFT test files duplicate the entire harness (reflection-backed wallet factory, request builder, inject helper, and the reward/brokerage rejection test) differing only in the wallet type and injected field name. Extract a shared base class or parameterized harness to avoid maintaining the same assertions in two places.</comment>
<file context>
@@ -0,0 +1,57 @@
+ }
+
+ @Test
+ public void rewardAndBrokerageMirrorsRejectMalformedAddresses() throws Exception {
+ GetRewardOnSolidityServlet reward = new GetRewardOnSolidityServlet();
+ inject(reward, "walletOnSolidity", walletOnSolidity());
</file context>
There was a problem hiding this comment.
2 issues found across 17 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="framework/src/test/java/org/tron/core/services/http/AddressQueryServletTestBase.java">
<violation number="1" location="framework/src/test/java/org/tron/core/services/http/AddressQueryServletTestBase.java:71">
P3: When a test address contains JSON-significant characters, `jsonRequest` creates malformed JSON instead of encoding the address as a JSON string. Escape the value with the project's JSON serializer (or otherwise quote it correctly) so this shared contract helper exercises the endpoint with the intended address.</violation>
</file>
<file name="framework/src/main/java/org/tron/core/services/http/Util.java">
<violation number="1" location="framework/src/main/java/org/tron/core/services/http/Util.java:705">
P2: For multibyte UTF-8 bodies, this check counts characters instead of request bytes and buffers well beyond `httpMaxMessageSize` before rejecting. Count bytes from the input stream while reading so the early bound matches the configured limit.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| new InputStreamReader(request.getInputStream()))) { | ||
| int read; | ||
| while ((read = reader.read(buffer)) != -1) { | ||
| if (sb.length() + read > limit) { |
There was a problem hiding this comment.
P2: For multibyte UTF-8 bodies, this check counts characters instead of request bytes and buffers well beyond httpMaxMessageSize before rejecting. Count bytes from the input stream while reading so the early bound matches the configured limit.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At framework/src/main/java/org/tron/core/services/http/Util.java, line 705:
<comment>For multibyte UTF-8 bodies, this check counts characters instead of request bytes and buffers well beyond `httpMaxMessageSize` before rejecting. Count bytes from the input stream while reading so the early bound matches the configured limit.</comment>
<file context>
@@ -673,14 +684,33 @@ private static String checkGetParam(HttpServletRequest request, String key) thro
+ new InputStreamReader(request.getInputStream()))) {
+ int read;
+ while ((read = reader.read(buffer)) != -1) {
+ if (sb.length() + read > limit) {
+ throw new Exception("body size is too big, the limit is " + limit);
+ }
</file context>
|
|
||
| protected static MockHttpServletRequest jsonRequest(String address, String contentType) { | ||
| MockHttpServletRequest request = postRequest(contentType); | ||
| String json = address == null ? "{}" : "{\"address\":\"" + address + "\"}"; |
There was a problem hiding this comment.
P3: When a test address contains JSON-significant characters, jsonRequest creates malformed JSON instead of encoding the address as a JSON string. Escape the value with the project's JSON serializer (or otherwise quote it correctly) so this shared contract helper exercises the endpoint with the intended address.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At framework/src/test/java/org/tron/core/services/http/AddressQueryServletTestBase.java, line 71:
<comment>When a test address contains JSON-significant characters, `jsonRequest` creates malformed JSON instead of encoding the address as a JSON string. Escape the value with the project's JSON serializer (or otherwise quote it correctly) so this shared contract helper exercises the endpoint with the intended address.</comment>
<file context>
@@ -0,0 +1,196 @@
+
+ protected static MockHttpServletRequest jsonRequest(String address, String contentType) {
+ MockHttpServletRequest request = postRequest(contentType);
+ String json = address == null ? "{}" : "{\"address\":\"" + address + "\"}";
+ request.setContent(json.getBytes(UTF_8));
+ return request;
</file context>
getContract and getContractInfo answer null for an address that is not well formed, before the account store is read.
7c48369 to
2c3bb5c
Compare
A string or number longer than 64 characters is rejected before BigDecimal sees it, and Permission_id must convert identically through both coercion paths, so a value one path silently reinterprets no longer gets through.
getAddress reports every way a request can fail to name an address as one fixed message, and the reward and brokerage servlets write it, so the fullnode, solidity and PBFT endpoints no longer differ on a given malformed request. An absent address is one of those ways: it used to be answered with the service default. The body is bounded while it is read, since this is the only body-reading path that does not go through PostParams.
Mint takes exactly one receive description; transfer takes one or two of each and, without an ask, a matching spend authority signature count. The counts are checked before the merge loops, because ByteUtil.merge copies the accumulated buffer on every iteration and checking afterwards would make an unbounded list quadratic.
… failure An amount string past 80 characters and a trigger input the builder rejects are answered as a ContractValidateException naming the argument, instead of escaping the wallet as an IllegalArgumentException.
2c3bb5c to
248cbe0
Compare
What does this PR do?
This PR hardens externally reachable API inputs before expensive or ambiguous processing:
BigDecimalconversionPermission_idexactly, rejects strings longer than 64 characters, and preserves existing supported numeric formsBigIntegerconversionWhy are these changes required?
Malformed inputs could previously trigger disproportionate CPU work, silently truncate or wrap numeric values, or return plausible results for structurally invalid addresses.
These changes reject invalid inputs before expensive conversion, encoding, storage access, or repeated buffer merging.
Compatibility notes:
getRewardandgetBrokerageno longer substitute a default for an address they never received.Util.getAddressnow either returns a valid address or throws, so a request that carries noaddressat all is rejected like any other unusable one:GET /wallet/getRewardwithout the parameter answered{"reward": 0}and now answers{"Error":"INVALID address"}. The same applies togetBrokerageand to both endpoints on/walletsolidityand the PBFT mirror, six in total. A caller that relied on the zero default has to send an address.Permission_idvalues with fractions, integer overflow, explicitnull, or string representations longer than 64 characters are rejectednode.allowShieldedTransactionApiflag, which is disabled by defaultThis PR has been tested by:
Follow up
Extra details
Summary by cubic
Hardens externally reachable API input validation and makes error responses consistent.
getReward/getBrokerage(and their/walletsolidity/PBFT mirrors) no longer default missing addresses; they now require a valid address and return {"Error":"INVALID address"} instead of 0/20.Bug Fixes
org.tron.core.services.http.Util#getAddressvalidates Base58Check and41...hex, bounds body size while reading, and returns fixed errors “INVALID address”/“INVALID JSON body” without echoing input.GetRewardServlet/GetBrokerageServletuse the unified handler so malformed requests are answered identically across FullNode/Solidity/PBFT.org.tron.core.Wallet#getContract/#getContractInforeject malformed addresses before any store access by returning null.Permission_idmust be an exact 32‑bit int and match across coercions, rejecting fractions, scientific forms, overflow, explicit null, and overlong strings; absent or ≤ 0 leaves the transaction unchanged.ContractValidateException(“invalid amount” or a specific argument error); thenode.allowShieldedTransactionApigate is unchanged.Migration
/wallet/getRewardand/wallet/getBrokerage(and/walletsolidity/PBFT mirrors) must send a validaddress; previous zero/20 defaults are removed.Written for commit 248cbe0. Summary will update on new commits.