While digging through a Javascript application, looking for bug bounty opportunities, I found an interesting case of destructuring giving a false sense of security about the contents of an untrusted string.
Imagine you have the following function:
const extractParts = (input) => {
if (!input || input.length < 10) return;
let [a, b, c] = input.split("|");
return { a, b, c };
};
This function, extractParts
, is expecting an input string composed of three values, a
, b
, and c
, concatenated together with "|"
characters, like "aaaaaa|b|c"
.
In the application where I found this code, b
and c
are constants of fixed length of one character, so the implied input.length >= 10
constraint was really making assertions on the length of a
. If the length of a
was less than 6
, there would be problems down the line.
Unfortunately, the destructuring of input.split("|")
on the next line doesn’t give us any guarantees about the real contents of input
. If input
contains only two "|"
characters, our constraint holds. However, our destructuring picks out the first three values of input.split("|")
, even if the resulting array contains more than three elements.
Imagine input
looks like this: "a|b|c|dddd"
. Passing this four-part input into extractParts
yields a resulting object that will cause problems for our application further down the line:
extractParts("a|b|c|dddd"); // { a: "a", b: "b", c: "c" }
Where did our final "dddd"
value go? It gave our input
just enough length to slip past our input.length < 10
guard, but is was thrown out in the destructuring step, resulting in a malformed a
! Our array destructuring gave us a false sense of security about the contents of our input
string.
A better way of writing our assertion might look something like this:
const extractParts = (input) => {
if (!input) return;
let [a, b, c] = input.split("|");
if (a.length < 6) return;
return { a, b, c };
};
Asserting on the length of a
directly prevents any unexpected inputs from slipping by unnoticed:
extractParts("a|b|c|dddd"); // undefined
Don’t let lenient destructuring give you a false sense of security about the shape and contents of untrusted data.