Hello,
I tried fuzzing sqids.encode by encoding a negative number or passing NULL (e.g., from an outer join or an explicit cast like ARRAY[NULL::int]), which causes sqids.encodeNumbers to enter an infinite loop, consume 100% CPU, and hang the PostgreSQL backend process. While this wouldn't happen with valid sequence IDs, malformed input database queries can trigger it:
# SELECT sqids.encode(array[1,2,4,-1]);
^CCancel request sent
ERROR: canceling statement due to user request
CONTEXT: PL/pgSQL function sqids.toid(bigint,text) line 16 at assignment
PL/pgSQL function sqids.encodenumbers(bigint[],text,integer,integer) line 67 at assignment
PL/pgSQL function sqids.encode(bigint[],text,integer) line 8 at assignment
To resolve this, I added a simple check in the first for loop that raises an exception when an array element is invalid.
Thanks for leaving the "-- raise notice" comments in the code, which made it easy to navigate without full algorithm analysis. I've created a patch that raises an explicit exception when encountering negative or NULL elements in the input array, but I don't really like it because it should be near the other checks at the beginning of sqids.encodeNumbers, and that would need another LOOP check:
--- install.sql 2026-08-29 11:14:14
+++ patched.sql 2026-08-29 11:19:00
@@ -174,6 +174,12 @@
--raise notice 'avi: % % %', a, v, i;
m := v % array_length(arr_alphabet, 1);
--raise notice 'm: %', m;
+
+ --raise notice 'Verify if m is not a negative integer or NULL'
+ IF m < 0 OR m IS NULL THEN
+ RAISE EXCEPTION 'Sqids: numbers must be non-negative integers, received %', m;
+ END IF;
+
char := ascii(arr_alphabet[m + 1]);
--raise notice 'char: %', char;
a := char + i + a;
@@ -330,4 +336,4 @@
END;
$$ LANGUAGE plpgsql;
Hello,
I tried fuzzing sqids.encode by encoding a negative number or passing NULL (e.g., from an outer join or an explicit cast like ARRAY[NULL::int]), which causes sqids.encodeNumbers to enter an infinite loop, consume 100% CPU, and hang the PostgreSQL backend process. While this wouldn't happen with valid sequence IDs, malformed input database queries can trigger it:
To resolve this, I added a simple check in the first for loop that raises an exception when an array element is invalid.
Thanks for leaving the "-- raise notice" comments in the code, which made it easy to navigate without full algorithm analysis. I've created a patch that raises an explicit exception when encountering negative or NULL elements in the input array, but I don't really like it because it should be near the other checks at the beginning of sqids.encodeNumbers, and that would need another LOOP check: