fix: Validate the validation_create secret parameter - #7934
Draft
SoubeDev wants to merge 2 commits into
Draft
Conversation
doValidationCreate read the optional secret with an unguarded asString(),
which throws for arrays and objects and silently stringifies every scalar.
The throw was swallowed by callMethod's catch-all, so a malformed value
produced a generic internal error rather than invalidParams, and the request
was recorded as a server fault in the perf log.
The coercion case is worse than a bad error code: parseGenericSeed accepts
any non-empty string as a passphrase, so {"secret": 12345} did not fail at
all. It hashed "12345" and returned a real validator key derived from the
printed form of a number the caller never meant as a passphrase. Booleans
behaved the same way; null coerced to "" and happened to be rejected already.
Guard the conversion with an isString() check and return invalidParams when
it fails. The check has to sit in the handler rather than in validationSeed,
whose only failure channel is nullopt and is already mapped to badSeed, which
must stay that way for a string secret that is not a seed.
This makes the handler stricter: a secret given as a number or a bool was
previously coerced and is now rejected. The command is admin only, and the
commandline builds the field from argv via asString(), so it is always a
string there and the parser is unaffected. An absent secret still picks a
random seed, and a string secret behaves exactly as before.
Add a ValidationCreate test suite, which did not exist; the two cases in
ValidatorRPC go through env.rpc(), which stringifies like the commandline
does and so cannot reach the handler with a non-string.
Fixes XRPLF#6763
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The entry was added with a placeholder because the pull request did not exist when the fix was committed. Point it at XRPLF#7934. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
doValidationCreate read the optional secret with an unguarded asString(), which throws for arrays and objects and silently stringifies every scalar. The throw was swallowed by callMethod's catch-all, so a malformed value produced a generic internal error rather than invalidParams, and the request was recorded as a server fault in the perf log.
The coercion case is worse than a bad error code: parseGenericSeed accepts any non-empty string as a passphrase, so {"secret": 12345} did not fail at all. It hashed "12345" and returned a real validator key derived from the printed form of a number the caller never meant as a passphrase. Booleans behaved the same way; null coerced to "" and happened to be rejected already.
Guard the conversion with an isString() check and return invalidParams when it fails. The check has to sit in the handler rather than in validationSeed, whose only failure channel is nullopt and is already mapped to badSeed, which must stay that way for a string secret that is not a seed.
This makes the handler stricter: a secret given as a number or a bool was previously coerced and is now rejected. The command is admin only, and the commandline builds the field from argv via asString(), so it is always a string there and the parser is unaffected. An absent secret still picks a random seed, and a string secret behaves exactly as before.
Add a ValidationCreate test suite, which did not exist; the two cases in ValidatorRPC go through env.rpc(), which stringifies like the commandline does and so cannot reach the handler with a non-string.
Fixes #6763
High Level Overview of Change
Context of Change
API Impact
libxrplchange (any change that may affectlibxrplor dependents oflibxrpl)