Skip to content

feat(rest): make qs arrayLimit configurable for query parameter parsing#11640

Open
KauanAfonso wants to merge 1 commit into
loopbackio:masterfrom
KauanAfonso:fix-qs-array-limit
Open

feat(rest): make qs arrayLimit configurable for query parameter parsing#11640
KauanAfonso wants to merge 1 commit into
loopbackio:masterfrom
KauanAfonso:fix-qs-array-limit

Conversation

@KauanAfonso

Copy link
Copy Markdown

Pull Request Description

Add configurable arrayLimit for query parameter parsing

Fixes #11396

Summary

This PR makes the qs arrayLimit for query parameter parsing configurable in LoopBack. Previously, query parameters with more than 20 array items were converted to objects with numeric keys, causing validation errors in LoopBack endpoints.

Problem

After the qs upgrade in commit 1eedfd5 (to address GHSA-6rw7-vpxm-498p), the default arrayLimit of 20 caused issues for APIs that need to handle more than 20 items in query parameter arrays. When this limit is exceeded, qs converts the array to an object to prevent DoS attacks with extremely large indices.

Example of the issue:

GET /products?ids=1&ids=2&ids=3...&ids=21
// Result: {ids: {0: '1', 1: '2', ..., 20: '21'}} ❌ (object instead of array)

Solution

Added a new queryParser configuration option to RestServerOptions that allows applications to customize the arrayLimit:

const app = new RestApplication({
  rest: {
    queryParser: {
      arrayLimit: 100, // Allow up to 100 items in query arrays
    },
  },
});

Changes Made

  1. Added queryParser configuration (packages/rest/src/rest.server.ts)

    • New optional queryParser property in RestServerResolvedOptions
    • Includes arrayLimit option with inline documentation
    • Default value: 20 (maintains backward compatibility)
  2. Configured Express query parser (packages/rest/src/rest.server.ts)

    • Modified _applyExpressSettings() to set custom query parser
    • Uses qs.parse() with configurable arrayLimit
    • Includes security settings: allowPrototypes: false, depth: 20
  3. Added comprehensive tests (packages/rest/src/__tests__/acceptance/request-parsing/array-limit.acceptance.ts)

    • Tests default behavior (20 items)
    • Tests custom limits (100 and 1000 items)
    • Verifies conversion to object when limit is exceeded
    • 7 test cases covering all scenarios

Usage Example

@get('/products')
async findByIds(
  @param.array('ids', 'query', {type: 'string'})
  ids: string[],
): Promise<Product[]> {
  return this.productRepository.find({
    where: {id: {inq: ids}},
  });
}

With the new configuration:

GET /products?ids=1&ids=2&ids=3...&ids=100
// Result: {ids: ['1', '2', ..., '100']} ✅ (array)

Breaking Changes

None. The default arrayLimit remains 20, maintaining backward compatibility.


Checklist

  • DCO (Developer Certificate of Origin) signed in all commits
  • npm test passes on your machine
  • New tests added or existing tests modified to cover all changes
  • Code conforms with the style guide
  • API Documentation in code was updated
  • Documentation in /docs/site was updated (can be added in follow-up if needed)
  • Affected artifact templates in packages/cli were updated (N/A)
  • Affected example projects in examples/* were updated (N/A)

Notes

  • Implementation follows existing Express configuration patterns in the codebase
  • Focuses only on query parsing (body parsing remains unchanged)
  • Tests cover default and custom array limits with comprehensive scenarios
  • Maintains backward compatibility with default limit of 20

Related Links

Signed-off-by: kauanAfonso <kauan.afonso@ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Query parameter array parsing broken for >20 items after qs upgrade (CVE fix side effect)

1 participant