-
-
-
-
- BUG-LQ006: doLedgerEntry missing type validation on 'binary' parameter allows non-boolean values
*Severity*: LOW
In doLedgerEntry (LedgerEntry.cpp line 944-945), the `binary` parameter is read with `context.params[jss::binary].asBool` without first checking `isBool`. While `asBool` doesn't throw (it does truthiness conversion — any non-zero integer, non-empty string, non-empty object/array all evaluate to true), this means that sending `"binary": 1` or `"binary": "yes"` or `"binary": {}` will all be treated as `true`. This is inconsistent with the `ledger` handler (Ledger.cpp lines 47-58) which explicitly validates `isBool` and returns `rpcINVALID_PARAMS` for non-boolean values. It's also inconsistent with the `ledger_data` handler (LedgerData.cpp lines 59-62) which also validates `isBool`.
*Root cause*: The doLedgerEntry handler skips type validation on the binary parameter, unlike other handlers in the same feature that properly check isBool first.
`src/xrpld/rpc/handlers/ledger/LedgerEntry.cpp:943-945`
```cpp
bool bNodeBinary = false;
if (context.params.isMember(jss::binary))
bNodeBinary = context.params[jss::binary].asBool;
```
*Invariant gap*: Input validation should be consistent across all handlers for the same parameter. The binary parameter should always require a boolean type.
*Suggested fix*: Add a type check before calling asBool: `if (!context.params[jss::binary].isBool) return RPC::expected_field_error(jss::binary, "boolean");`
<details>
<summary>Triage Details</summary>
*Status*: ✅ Verified
Confirmed. LedgerEntry.cpp lines 943-945 use `context.params[jss::binary].asBool` without first checking `isBool`. The Ledger handler (lines 47-58) and LedgerData handler (lines 59-62) both validate `isBool` first. The impact is minimal — asBool performs truthiness conversion without throwing, so non-boolean values like integers or strings are accepted and silently converted. This is an input validation inconsistency, not a security vulnerability.
*Final severity*: INFORMATIONAL
*Action*: Backlog
Input validation inconsistency across handlers for the binary parameter. No security impact — asBool handles non-boolean types gracefully. Fix for API consistency.
Add `if (!context.params[jss::binary].isBool) return RPC::expected_field_error(jss::binary, "boolean");` before the asBool call, consistent with other handlers.
</details>
Additional Context
RPC Verdict Report
Pattern: IV — doLedgerEntry missing type validation on binary parameter
Handler: doLedgerEntry in rippled/src/xrpld/rpc/handlers/ledger/LedgerEntry.cpp:944-945
Registered Role: Role::USER — public | Transport: HTTP / WS
Verdict: ⚠️ Code Improvement Needed | Confidence: 86%
Root Cause
params[jss::binary] is read without isBool check. Non-boolean inputs cause Json::LogicError caught as rpcINTERNAL. Add isBool validation before asBool.
// LedgerEntry.cpp:944-945 — BUG: no isBool check
bool const bBinary = params[jss::binary].asBool;
// ^^^^^^^
// throws Json::LogicError if binary is a string, array, or object!
// e.g., params["binary"] = "yes" → rpcINTERNAL
Suggested Fix
// Add isBool guard:
if (params.isMember(jss::binary) && !params[jss::binary].isBool)
return rpcError(rpcINVALID_PARAMS);
bool const bBinary = params.isMember(jss::binary) && params[jss::binary].asBool;
Reproduction Tests — src/test/rpc/LedgerEntry_test.cpp
void testLedgerEntryBinaryString(FeatureBitset features)
{
testcase("ledger_entry: string binary returns rpcINVALID_PARAMS");
using namespace jtx;
Env env{*this, features};
env.close;
Json::Value params;
params[jss::account_root] = env.master.human;
params[jss::binary] = "yes"; // string instead of bool!
auto jv = env.rpc("json", "ledger_entry", params.toStyledString);
auto const& result = jv[jss::result];
BEAST_EXPECT(result.isMember(jss::error));
// BEFORE fix: rpcINTERNAL (Json::LogicError from asBool)
// AFTER fix: rpcINVALID_PARAMS
BEAST_EXPECT(result[jss::error_code].asInt != rpcINTERNAL);
}
void testLedgerEntryBinaryInteger(FeatureBitset features)
{
testcase("ledger_entry: integer binary returns rpcINVALID_PARAMS");
using namespace jtx;
Env env{*this, features};
env.close;
Json::Value params;
params[jss::account_root] = env.master.human;
params[jss::binary] = 1; // integer instead of bool!
auto jv = env.rpc("json", "ledger_entry", params.toStyledString);
auto const& result = jv[jss::result];
BEAST_EXPECT(result.isMember(jss::error));
BEAST_EXPECT(result[jss::error_code].asInt != rpcINTERNAL);
}
void testLedgerEntryBinaryTrue(FeatureBitset features)
{
testcase("ledger_entry: binary=true returns serialized hex");
using namespace jtx;
Env env{*this, features};
env.close;
Json::Value params;
params[jss::account_root] = env.master.human;
params[jss::binary] = true;
auto jv = env.rpc("json", "ledger_entry", params.toStyledString);
auto const& result = jv[jss::result];
// Valid bool — should not return rpcINTERNAL
if (result.isMember(jss::error))
BEAST_EXPECT(result[jss::error_code].asInt != rpcINTERNAL);
else
BEAST_EXPECT(result.isMember(jss::node_binary));
}
void testLedgerEntryBinaryFalse(FeatureBitset features)
{
testcase("ledger_entry: binary=false returns JSON object");
using namespace jtx;
Env env{*this, features};
env.close;
Json::Value params;
params[jss::account_root] = env.master.human;
params[jss::binary] = false;
auto jv = env.rpc("json", "ledger_entry", params.toStyledString);
auto const& result = jv[jss::result];
if (result.isMember(jss::error))
BEAST_EXPECT(result[jss::error_code].asInt != rpcINTERNAL);
else
BEAST_EXPECT(result.isMember(jss::node));
}
Build & Run
cmake --build rippled/build/Debug --target rippled
rippled/build/Debug/rippled --unittest ripple.rpc.LedgerEntry
Co-authored by Augment Code
*Severity*: LOW
In doLedgerEntry (LedgerEntry.cpp line 944-945), the `binary` parameter is read with `context.params[jss::binary].asBool` without first checking `isBool`. While `asBool` doesn't throw (it does truthiness conversion — any non-zero integer, non-empty string, non-empty object/array all evaluate to true), this means that sending `"binary": 1` or `"binary": "yes"` or `"binary": {}` will all be treated as `true`. This is inconsistent with the `ledger` handler (Ledger.cpp lines 47-58) which explicitly validates `isBool` and returns `rpcINVALID_PARAMS` for non-boolean values. It's also inconsistent with the `ledger_data` handler (LedgerData.cpp lines 59-62) which also validates `isBool`.
*Root cause*: The doLedgerEntry handler skips type validation on the binary parameter, unlike other handlers in the same feature that properly check isBool first.
`src/xrpld/rpc/handlers/ledger/LedgerEntry.cpp:943-945`
```cpp
bool bNodeBinary = false;
if (context.params.isMember(jss::binary))
bNodeBinary = context.params[jss::binary].asBool;
```
*Invariant gap*: Input validation should be consistent across all handlers for the same parameter. The binary parameter should always require a boolean type.
*Suggested fix*: Add a type check before calling asBool: `if (!context.params[jss::binary].isBool) return RPC::expected_field_error(jss::binary, "boolean");`
<details>
<summary>Triage Details</summary>
*Status*: ✅ Verified
Confirmed. LedgerEntry.cpp lines 943-945 use `context.params[jss::binary].asBool` without first checking `isBool`. The Ledger handler (lines 47-58) and LedgerData handler (lines 59-62) both validate `isBool` first. The impact is minimal — asBool performs truthiness conversion without throwing, so non-boolean values like integers or strings are accepted and silently converted. This is an input validation inconsistency, not a security vulnerability.
*Final severity*: INFORMATIONAL
*Action*: Backlog
Input validation inconsistency across handlers for the binary parameter. No security impact — asBool handles non-boolean types gracefully. Fix for API consistency.
Add `if (!context.params[jss::binary].isBool) return RPC::expected_field_error(jss::binary, "boolean");` before the asBool call, consistent with other handlers.
</details>
Additional Context
RPC Verdict Report
Pattern: IV — doLedgerEntry missing type validation on binary parameter
Handler: doLedgerEntry in rippled/src/xrpld/rpc/handlers/ledger/LedgerEntry.cpp:944-945
Registered Role: Role::USER — public | Transport: HTTP / WS
Verdict:⚠️ Code Improvement Needed | Confidence: 86%
Root Cause
params[jss::binary] is read without isBool check. Non-boolean inputs cause Json::LogicError caught as rpcINTERNAL. Add isBool validation before asBool.
Suggested Fix
Reproduction Tests — src/test/rpc/LedgerEntry_test.cpp
Build & Run
Co-authored by Augment Code