Skip to content

feat(crypto): shielded transaction API security enhancement#15

Open
Federico2014 wants to merge 1 commit intodevelopfrom
fix/shielded-api-security
Open

feat(crypto): shielded transaction API security enhancement#15
Federico2014 wants to merge 1 commit intodevelopfrom
fix/shielded-api-security

Conversation

@Federico2014
Copy link
Copy Markdown
Owner

@Federico2014 Federico2014 commented Apr 15, 2026

What does this PR do?

Enhances the security of shielded transaction APIs by adding overflow protection, tightening default configuration, and cleaning up unused artifacts.

  1. Added integer overflow protection in ZenTransactionBuilder and ShieldedTRC20ParametersBuilder: replaced raw +=/-= on valueBalance with StrictMathWrapper.addExact()/subtractExact(), which throw ArithmeticException on overflow. Overflow validation is performed before mutating builder state (spends/receives lists), ensuring the builder remains consistent if an overflow is detected.
  2. Wrapped createShieldedTransaction, createShieldedTransactionWithoutSpendAuthSig, createShieldedContractParameters, and createShieldedContractParametersWithoutAsk in try/catch ArithmeticException to convert overflow to ZksnarkException("shielded amount overflow")
  3. Changed the default value of allowShieldedTransactionApi from true to false to reduce exposure by default, since some shielded transaction APIs require passing private keys as parameters
  4. Updated config.conf with an explicit warning advising users to only invoke these APIs locally
  5. Removed sprout-verifying.key from the repository root — the file was not referenced by any code
  6. Updated test fixtures to explicitly enable allowShieldedTransactionApi and properly save/restore the flag

Why are these changes required?

  • valueBalance was accumulated via raw +=/-= without overflow checks, allowing crafted inputs to silently wrap around long range and produce invalid balances
  • Shielded transaction APIs accept private keys as parameters — enabling them by default on public-facing nodes risks private key leakage
  • sprout-verifying.key was an unreferenced artifact that added unnecessary repository bloat

⚠️ Breaking Changes:

  • allowShieldedTransactionApi default changed from true to false — nodes that previously relied on the default will find shielded transaction APIs disabled after upgrade. Fix: explicitly set allowShieldedTransactionApi = true in config.conf.

This PR has been tested by:

  • Unit Tests — ShieldedTransferActuatorTest, ArgsTest, ShieldedTRC20BuilderTest, CreateSpendAuthSigServletTest, MerkleContainerTest
  • Build passes (./gradlew clean build -x test)

Follow up

No consensus logic or on-chain state transitions affected.

Extra details

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 15, 2026

📝 Walkthrough

Walkthrough

This PR changes the default behavior of shielded transaction APIs from enabled to disabled, implements strict arithmetic overflow checking in shielded transaction builders using StrictMathWrapper, adds exception handling in the wallet to catch arithmetic exceptions from the builders, and updates tests to explicitly enable the API when needed for test execution.

Changes

Cohort / File(s) Summary
Configuration and Default Behavior
common/src/main/java/org/tron/common/parameter/CommonParameter.java, framework/src/main/java/org/tron/core/config/args/Args.java, framework/src/main/resources/config.conf
Changed default for allowShieldedTransactionApi from true to false across parameter defaults, config fallback logic, and documentation. Added security warnings in config comments about private key leakage risks and local-only usage recommendations.
Arithmetic Overflow Protection
framework/src/main/java/org/tron/core/zen/ShieldedTRC20ParametersBuilder.java, framework/src/main/java/org/tron/core/zen/ZenTransactionBuilder.java
Replaced unchecked arithmetic (+=, -=) with StrictMathWrapper.addExact() and subtractExact() for valueBalance calculations during spend/output aggregation to detect potential overflow/underflow conditions.
Wallet Exception Handling
framework/src/main/java/org/tron/core/Wallet.java
Wrapped shielded transaction building and shielded TRC20 parameter construction in try/catch blocks to convert ArithmeticException into ZksnarkException("shielded amount overflow"), replacing generic error messages like "Unbalanced burn!".
Test Lifecycle Management
framework/src/test/java/org/tron/core/ShieldedTRC20BuilderTest.java, framework/src/test/java/org/tron/core/services/http/CreateSpendAuthSigServletTest.java, framework/src/test/java/org/tron/core/zksnark/MerkleContainerTest.java
Added @BeforeClass/@AfterClass lifecycle hooks to store and restore original allowShieldedTransactionApi state, ensuring tests enable the API for execution and restore prior configuration afterward.
Test Behavior Verification
framework/src/test/java/org/tron/core/config/args/ArgsTest.java, framework/src/test/java/org/tron/core/actuator/ShieldedTransferActuatorTest.java, framework/src/test/java/org/tron/core/services/RpcApiServicesTest.java
Added tests verifying default allowShieldedTransactionApi is false, explicit enabling works, shielded transfer validation succeeds when API is disabled, and handling of ArithmeticException from strict arithmetic in validation flows.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • Changes address the security concern and code quality objective of disabling shielded transaction APIs by default and implementing strict arithmetic overflow checking to prevent undetected amount overflow conditions in shielded transactions.

Poem

🐰 By default, the shield doors stay locked tight,
Strict math guards against overflow blight!
Tests capture config, restore with care,
Safe shielded transactions everywhere! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.95% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(crypto): shielded transaction API security enhancement' clearly and directly describes the main change: enhancing security for shielded transaction APIs through overflow protection and disabling by default.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/shielded-api-security

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 13 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/main/java/org/tron/core/zen/ShieldedTRC20ParametersBuilder.java">

<violation number="1" location="framework/src/main/java/org/tron/core/zen/ShieldedTRC20ParametersBuilder.java:552">
P2: Update `valueBalance` before appending to the builder state. As written, an overflow throws after `spends`/`receives` has already been mutated, leaving the builder inconsistent for any later `build()` call.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@Federico2014 Federico2014 force-pushed the fix/shielded-api-security branch from 5c2b8f4 to ba1b665 Compare April 15, 2026 09:52
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (4)
framework/src/main/java/org/tron/core/config/args/Args.java (1)

719-730: Emit a startup warning when the new secure default is applied.

When neither config key is present, the node now silently falls back to false, and operators only discover the breaking change later when shielded endpoints start returning ShieldedTransactionApi is not allowed. A one-time warning here would make upgrades much easier to diagnose.

Suggested change
     } else {
       PARAMETER.allowShieldedTransactionApi = false;
+      logger.warn("node.allowShieldedTransactionApi is unset; shielded transaction APIs are "
+          + "disabled by default. Set node.allowShieldedTransactionApi = true to enable them.");
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/src/main/java/org/tron/core/config/args/Args.java` around lines 719
- 730, The code path in Args that sets PARAMETER.allowShieldedTransactionApi to
false when neither ConfigKey.ALLOW_SHIELDED_TRANSACTION_API nor
ConfigKey.NODE_FULLNODE_ALLOW_SHIELDED_TRANSACTION is present should emit a
one-time startup warning; update the else branch in the Args class (where
PARAMETER.allowShieldedTransactionApi is set to false) to call logger.warn (or
logger.info if you prefer severity) with a clear message that the node defaulted
to disallowing shielded transaction API and operators should set
node.allowShieldedTransactionApi=true to re-enable it, so operators see this on
upgrade rather than discovering it later at runtime.
framework/src/test/java/org/tron/core/config/args/ArgsTest.java (1)

364-387: Test the config path, not just the setter.

testExplicitEnableShieldedTransactionApi() currently proves the field setter works, but the behavior that changed is in Args.applyConfigParams(). Adding assertions for node.allowShieldedTransactionApi=true and the deprecated fallback key would protect the parsing and precedence logic that can actually regress.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/src/test/java/org/tron/core/config/args/ArgsTest.java` around lines
364 - 387, Update testExplicitEnableShieldedTransactionApi() to exercise the
config parsing path instead of just the setter: call Args.setParam(...) with a
config that contains node.allowShieldedTransactionApi=true (and add a separate
assertion or subtest that the deprecated fallback key
allowShieldedTransactionApi=true is also recognized), then call
Args.getInstance().isAllowShieldedTransactionApi() (after
Args.applyConfigParams() if that’s required) and assert it is true; do not use
Args.getInstance().setAllowShieldedTransactionApi(true) in this test so it
verifies Args.applyConfigParams()/Args.setParam() parsing and precedence logic.
framework/src/main/java/org/tron/core/Wallet.java (1)

2370-2370: Extract duplicated overflow message into a shared constant.

The same literal appears in multiple methods; centralizing it reduces drift risk during future edits.

♻️ Proposed refactor
@@
   private static final String SHIELDED_ID_NOT_ALLOWED = "ShieldedTransactionApi is not allowed";
+  private static final String SHIELDED_AMOUNT_OVERFLOW = "shielded amount overflow";
@@
-      throw new ZksnarkException("shielded amount overflow");
+      throw new ZksnarkException(SHIELDED_AMOUNT_OVERFLOW);
@@
-      throw new ZksnarkException("shielded amount overflow");
+      throw new ZksnarkException(SHIELDED_AMOUNT_OVERFLOW);
@@
-        throw new ZksnarkException("shielded amount overflow");
+        throw new ZksnarkException(SHIELDED_AMOUNT_OVERFLOW);
@@
-      throw new ZksnarkException("shielded amount overflow");
+      throw new ZksnarkException(SHIELDED_AMOUNT_OVERFLOW);
@@
-        throw new ZksnarkException("shielded amount overflow");
+        throw new ZksnarkException(SHIELDED_AMOUNT_OVERFLOW);
@@
-      throw new ZksnarkException("shielded amount overflow");
+      throw new ZksnarkException(SHIELDED_AMOUNT_OVERFLOW);

Also applies to: 2474-2474, 3661-3661, 3733-3733, 3797-3797, 3858-3858

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/src/main/java/org/tron/core/Wallet.java` at line 2370, Extract the
repeated literal "shielded amount overflow" from Wallet.java into a single
shared constant (for example a private static final String
SHIELDED_AMOUNT_OVERFLOW_MSG) declared in the Wallet class, then replace each
direct throw new ZksnarkException("shielded amount overflow") occurrence (e.g.,
the throws inside the methods around the existing calls at the current throw
sites) with throw new ZksnarkException(SHIELDED_AMOUNT_OVERFLOW_MSG); ensure all
listed occurrences (the ones currently throwing ZksnarkException with that exact
literal) are updated to use the new constant.
framework/src/test/java/org/tron/core/actuator/ShieldedTransferActuatorTest.java (1)

1360-1403: Restore the original API flag value instead of hardcoding true.

At Line 1402, forcing true can leak state if class setup/defaults change. Snapshot and restore the pre-test value instead.

♻️ Suggested change
   `@Test`
   public void shieldedTransferValidationWorksWhenApiDisabled() {
+    boolean originalAllowShieldedTransactionApi = Args.getInstance().allowShieldedTransactionApi;
     // Disable the shielded API (this should NOT affect transaction validation)
     Args.getInstance().setAllowShieldedTransactionApi(false);
@@
     } finally {
-      // Restore default for other tests
-      Args.getInstance().setAllowShieldedTransactionApi(true);
+      // Restore previous value for other tests
+      Args.getInstance().setAllowShieldedTransactionApi(originalAllowShieldedTransactionApi);
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@framework/src/test/java/org/tron/core/actuator/ShieldedTransferActuatorTest.java`
around lines 1360 - 1403, The test currently hardcodes restoring the API flag
with Args.getInstance().setAllowShieldedTransactionApi(true) which can leak
state; capture the original flag before changing it (e.g. boolean originalAllow
= Args.getInstance().isAllowShieldedTransactionApi()), use
Args.getInstance().setAllowShieldedTransactionApi(false) for the test, and in
the finally block restore the original value with
Args.getInstance().setAllowShieldedTransactionApi(originalAllow) so the test
leaves global state as it was; update ShieldedTransferActuatorTest around the
existing setAllowShieldedTransactionApi calls and finally block to use this
pattern.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@framework/src/main/java/org/tron/core/config/args/Args.java`:
- Around line 719-730: The code path in Args that sets
PARAMETER.allowShieldedTransactionApi to false when neither
ConfigKey.ALLOW_SHIELDED_TRANSACTION_API nor
ConfigKey.NODE_FULLNODE_ALLOW_SHIELDED_TRANSACTION is present should emit a
one-time startup warning; update the else branch in the Args class (where
PARAMETER.allowShieldedTransactionApi is set to false) to call logger.warn (or
logger.info if you prefer severity) with a clear message that the node defaulted
to disallowing shielded transaction API and operators should set
node.allowShieldedTransactionApi=true to re-enable it, so operators see this on
upgrade rather than discovering it later at runtime.

In `@framework/src/main/java/org/tron/core/Wallet.java`:
- Line 2370: Extract the repeated literal "shielded amount overflow" from
Wallet.java into a single shared constant (for example a private static final
String SHIELDED_AMOUNT_OVERFLOW_MSG) declared in the Wallet class, then replace
each direct throw new ZksnarkException("shielded amount overflow") occurrence
(e.g., the throws inside the methods around the existing calls at the current
throw sites) with throw new ZksnarkException(SHIELDED_AMOUNT_OVERFLOW_MSG);
ensure all listed occurrences (the ones currently throwing ZksnarkException with
that exact literal) are updated to use the new constant.

In
`@framework/src/test/java/org/tron/core/actuator/ShieldedTransferActuatorTest.java`:
- Around line 1360-1403: The test currently hardcodes restoring the API flag
with Args.getInstance().setAllowShieldedTransactionApi(true) which can leak
state; capture the original flag before changing it (e.g. boolean originalAllow
= Args.getInstance().isAllowShieldedTransactionApi()), use
Args.getInstance().setAllowShieldedTransactionApi(false) for the test, and in
the finally block restore the original value with
Args.getInstance().setAllowShieldedTransactionApi(originalAllow) so the test
leaves global state as it was; update ShieldedTransferActuatorTest around the
existing setAllowShieldedTransactionApi calls and finally block to use this
pattern.

In `@framework/src/test/java/org/tron/core/config/args/ArgsTest.java`:
- Around line 364-387: Update testExplicitEnableShieldedTransactionApi() to
exercise the config parsing path instead of just the setter: call
Args.setParam(...) with a config that contains
node.allowShieldedTransactionApi=true (and add a separate assertion or subtest
that the deprecated fallback key allowShieldedTransactionApi=true is also
recognized), then call Args.getInstance().isAllowShieldedTransactionApi() (after
Args.applyConfigParams() if that’s required) and assert it is true; do not use
Args.getInstance().setAllowShieldedTransactionApi(true) in this test so it
verifies Args.applyConfigParams()/Args.setParam() parsing and precedence logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 40c590e1-4bfb-4437-ab59-1899269c705d

📥 Commits

Reviewing files that changed from the base of the PR and between 208807d and ba1b665.

📒 Files selected for processing (13)
  • common/src/main/java/org/tron/common/parameter/CommonParameter.java
  • framework/src/main/java/org/tron/core/Wallet.java
  • framework/src/main/java/org/tron/core/config/args/Args.java
  • framework/src/main/java/org/tron/core/zen/ShieldedTRC20ParametersBuilder.java
  • framework/src/main/java/org/tron/core/zen/ZenTransactionBuilder.java
  • framework/src/main/resources/config.conf
  • framework/src/test/java/org/tron/core/ShieldedTRC20BuilderTest.java
  • framework/src/test/java/org/tron/core/actuator/ShieldedTransferActuatorTest.java
  • framework/src/test/java/org/tron/core/config/args/ArgsTest.java
  • framework/src/test/java/org/tron/core/services/RpcApiServicesTest.java
  • framework/src/test/java/org/tron/core/services/http/CreateSpendAuthSigServletTest.java
  • framework/src/test/java/org/tron/core/zksnark/MerkleContainerTest.java
  • sprout-verifying.key

@Federico2014 Federico2014 force-pushed the fix/shielded-api-security branch 2 times, most recently from 0666f3c to 4512b7a Compare April 15, 2026 10:14
@Federico2014 Federico2014 force-pushed the fix/shielded-api-security branch from 4512b7a to f301e6f Compare April 15, 2026 10:31
Copy link
Copy Markdown
Owner Author

@Federico2014 Federico2014 left a comment

Choose a reason for hiding this comment

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

Thanks for the review. Responses to each nitpick:

  1. Args.java — startup warning when default is applied: The else branch means the user never configured this key at all — most nodes don't use shielded APIs, so a warning here would just be noise. The config.conf comment already documents the change. Won't fix.

  2. ArgsTest — test config parsing path: These two tests have been merged into one in the latest commit. The current pattern (setter-based) is consistent with other tests in ArgsTest. Won't fix.

  3. Wallet.java — extract duplicated overflow message: These are exception messages only, not used in logic. Keeping them inline is fine for this scope. Won't fix.

  4. ShieldedTransferActuatorTest — restore original flag: Already fixed in 4512b7a — the test now saves and restores the original value via boolean orig.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant