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.