What changed, and why it matters
This is a small code cleanup that switches to a helper function which unescapes JSON strings without making an extra copy. The only behavior change is that invalid escape sequences in command usage strings are now rejected instead of silently accepted unchanged. There is no obvious security vulnerability being fixed, and no evidence of an exploit or disclosure.
No immediate action required. Treat as routine refactoring. If auditing, verify that callers of jsonrpc_command_add() handle a false return correctly and that rejecting invalid escape sequences does not break any legitimate usage strings.
Security signals we found
Behavior change: invalid escape sequences in usage strings are now rejected rather than silently accepted
No mention of vulnerability, CVE, security bug, or exploit in commit message or diff
No references to external security advisories or disclosures supplied
Evidence from the diff
The commit replaces calls to json_escape_string_() followed by json_escape_unescape() with a single json_escape_unescape_len() call across json_param.c, a test, jsonrpc.c, and runes.c. In jsonrpc_command_add(), the previous behavior fell back to using the raw usage string if unescaping failed; now it returns false. The commit message explicitly notes this change. This is primarily a refactoring/efficiency improvement, not a security patch.
Changed components
common/json_param.ccommon/test/run-bolt12_decode.clightningd/jsonrpc.clightningd/runes.cInspect captured patch +8 / −20
diff --git a/common/json_param.c b/common/json_param.c
index b95952dd..1a761112 100644
--- a/common/json_param.c
+++ b/common/json_param.c
@@ -444,11 +444,9 @@ struct command_result *param_escaped_string(struct command *cmd,
const char **str)
{
if (tok->type == JSMN_STRING) {
- struct json_escape *esc;
/* jsmn always gives us ~ well-formed strings. */
- esc = json_escape_string_(cmd, buffer + tok->start,
- tok->end - tok->start);
- *str = json_escape_unescape(cmd, esc);
+ *str = json_escape_unescape_len(cmd, buffer + tok->start,
+ tok->end - tok->start);
if (*str)
return NULL;
}
diff --git a/common/test/run-bolt12_decode.c b/common/test/run-bolt12_decode.c
index ae4cd8b4..4702d23f 100644
--- a/common/test/run-bolt12_decode.c
+++ b/common/test/run-bolt12_decode.c
@@ -190,13 +190,11 @@ int main(int argc, char *argv[])
char *fail;
const char *str;
size_t dlen;
- struct json_escape *esc;
assert(json_to_bool(json, json_get_member(json, t, "valid"), &valid));
strtok = json_get_member(json, t, "string");
- esc = json_escape_string_(tmpctx, json + strtok->start,
- strtok->end - strtok->start);
- str = json_escape_unescape(tmpctx, esc);
+ str = json_escape_unescape_len(tmpctx, json + strtok->start,
+ strtok->end - strtok->start);
actual = (string_to_data(tmpctx, str, strlen(str),
"lno", &dlen, &fail) != NULL);
assert(actual == valid);
diff --git a/lightningd/jsonrpc.c b/lightningd/jsonrpc.c
index 4b240808..43286a28 100644
--- a/lightningd/jsonrpc.c
+++ b/lightningd/jsonrpc.c
@@ -1393,20 +1393,14 @@ static void setup_command_usage(struct lightningd *ld,
bool jsonrpc_command_add(struct jsonrpc *rpc, struct json_command *command,
const char *usage TAKES)
{
- struct json_escape *esc;
const char *unescaped;
if (!command_add(rpc, command))
return false;
- esc = json_escape_string_(tmpctx, usage, strlen(usage));
- unescaped = json_escape_unescape(command, esc);
+ unescaped = json_escape_unescape_len(command, usage, strlen(usage));
if (!unescaped)
- unescaped = tal_strdup(command, usage);
- else {
- if (taken(usage))
- tal_free(usage);
- }
+ return false;
strmap_add(&rpc->usagemap, command->name, unescaped);
tal_add_destructor2(command, destroy_json_command, rpc);
diff --git a/lightningd/runes.c b/lightningd/runes.c
index 9a4c6fde..77be7a30 100644
--- a/lightningd/runes.c
+++ b/lightningd/runes.c
@@ -484,10 +484,8 @@ static struct rune_altern *rune_altern_from_json(const tal_t *ctx,
/* We still need to unescape here, for \\ -> \. JSON doesn't
* allow unnecessary \ */
const char *unescape;
- struct json_escape *e = json_escape_string_(tmpctx,
- buffer + tok->start,
- tok->end - tok->start);
- unescape = json_escape_unescape(tmpctx, e);
+ unescape = json_escape_unescape_len(tmpctx, buffer + tok->start,
+ tok->end - tok->start);
if (!unescape)
return NULL;
Why this scored 20/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.