identity: add identity string validation
What changed, and why it matters
This commit adds a safety check to Blockstream Jade's 'sign identity' feature. Before the change, the device would accept any identity string a connected app sent. Now it rejects identities that contain non-printable or unusual characters. This reduces the risk that a malicious or buggy app could trick the user into signing an identity they did not intend to, or could smuggle control characters into a string shown on the device's screen.
Treat as a security hardening fix and include in release notes. Review whether other RPC endpoints that accept user-facing strings perform similar validation, and consider whether identity strings also need length and character-set limits beyond isprint. No urgent advisory is required based on the diff alone, but users should update firmware once a release containing this commit is available.
Security signals we found
Input validation added to a signing/identity process
New length-bounded string helper reduces reliance on null-termination
Rejection of non-printable characters in user-presented identity string
Potential UI manipulation / display spoofing hardening
No explicit CVE, advisory, or researcher attribution in commit
Evidence from the diff
The patch introduces string_n_all(), a length-bounded variant of the existing string_all() helper, and uses it in sign_identity_process() to validate that the ‘identity’ RPC parameter consists solely of printable characters (isprint). Previously the identity was parsed from CBOR but not validated. The change rejects the request with CBOR_RPC_BAD_PARAMETERS if validation fails. This is a hardening/validation fix; the diff does not by itself prove an exploitable vulnerability exists, but it removes an unbounded, unvalidated input path used in a signing workflow.
Changed components
main/process/sign_identity.cmain/utils/util.hBlockstream Jade identity signing RPCInspect captured patch +22 / −0
diff --git a/main/process/sign_identity.c b/main/process/sign_identity.c
index a9a3fa8..32f36f7 100644
--- a/main/process/sign_identity.c
+++ b/main/process/sign_identity.c
@@ -1,10 +1,13 @@
#ifndef AMALGAMATED_BUILD
+#include <ctype.h>
+
#include "../jade_assert.h"
#include "../jade_wally_verify.h"
#include "../keychain.h"
#include "../process.h"
#include "../ui.h"
#include "../utils/cbor_rpc.h"
+#include "../utils/util.h"
#include "../button_events.h"
@@ -57,6 +60,12 @@ void sign_identity_process(void* process_ptr)
goto cleanup;
}
+ // Identity must be a string of printable characters
+ if (!string_n_all(identity, identity_len, isprint)) {
+ jade_process_reject_message(process, CBOR_RPC_BAD_PARAMETERS, "Invalid identity string");
+ goto cleanup;
+ }
+
const uint8_t* challenge = NULL;
size_t challenge_len = 0;
rpc_get_bytes_ptr("challenge", ¶ms, &challenge, &challenge_len);
diff --git a/main/utils/util.h b/main/utils/util.h
index c4f1760..45818e5 100644
--- a/main/utils/util.h
+++ b/main/utils/util.h
@@ -75,6 +75,19 @@ static inline bool string_all(const char* s, int (*fntest)(int))
return true;
}
+static inline bool string_n_all(const char* s, size_t len, int (*fntest)(int))
+{
+ JADE_ASSERT(s);
+ JADE_ASSERT(fntest);
+
+ while (len--) {
+ if (!fntest(*s++)) {
+ return false;
+ }
+ }
+ return true;
+}
+
static inline void map_string(char* s, int (*fnmap)(int))
{
JADE_ASSERT(s);
Why this scored 46/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.