diff --git a/server/utils/queries/libraryBrowseCursor.js b/server/utils/queries/libraryBrowseCursor.js index 15a33ff04..67b79645a 100644 --- a/server/utils/queries/libraryBrowseCursor.js +++ b/server/utils/queries/libraryBrowseCursor.js @@ -15,6 +15,10 @@ function decodeBrowseCursor(cursor) { throw invalidBrowseCursor() } + if (!decoded || typeof decoded !== 'object' || Array.isArray(decoded)) { + throw invalidBrowseCursor() + } + if (!Array.isArray(decoded.keys) || !Array.isArray(decoded.values) || decoded.keys.length !== decoded.values.length) { throw new Error('Cursor is missing the full ordered key set') } diff --git a/test/server/utils/libraryBrowseCursor.test.js b/test/server/utils/libraryBrowseCursor.test.js index 2a48a1f3b..fd7741787 100644 --- a/test/server/utils/libraryBrowseCursor.test.js +++ b/test/server/utils/libraryBrowseCursor.test.js @@ -59,4 +59,10 @@ describe('libraryBrowseCursor', () => { expect(() => decodeBrowseCursor(malformedJsonCursor)).to.throw('Invalid browse cursor') }) + + it('rejects decoded non-object json payloads with a controlled invalid-cursor error', () => { + const nonObjectCursor = Buffer.from('null', 'utf8').toString('base64url') + + expect(() => decodeBrowseCursor(nonObjectCursor)).to.throw('Invalid browse cursor') + }) })