express icon indicating copy to clipboard operation
express copied to clipboard

feat: add CORS-aware ETag modes and configurable query parser options

Open iAn-P1nt0 opened this issue 1 month ago • 0 comments

Overview

This PR introduces two independent enhancements to Express.js that address long-standing issues with CDN caching and query string handling.

Changes Included

1. CORS-Aware ETag Generation (Fixes #5986)

Adds new ETag modes that include response headers in ETag calculation to prevent cache conflicts when serving content to multiple origins through CDNs.

New ETag modes:

  • 'weak-cors': Weak ETag including Access-Control-Allow-Origin header
  • 'strong-cors': Strong ETag including Access-Control-Allow-Origin header

Problem solved: CDNs returning 304 Not Modified responses that omit CORS headers, causing browsers to apply cached CORS headers from different origins, resulting in CORS errors.

Usage: `app.set('etag', 'weak-cors');

app.use(function(req, res) { res.set('Access-Control-Allow-Origin', req.get('Origin')); res.send('content'); });`

Implementation:

  • Extends createETagGenerator to accept includeHeaders option
  • Updates res.send() to pass response headers to ETag function
  • Maintains full backward compatibility with existing ETag modes
  • Falls back to body-only hashing when CORS headers are not present

2. Configurable Query Parser Options (Fixes #5878)

Adds ability to configure qs library options when using the extended query parser, addressing silent parameter truncation and providing better security controls.

New API: app.set('query parser', 'extended'); app.set('query parser options', { parameterLimit: 5000, // Increase from default 1000 arrayLimit: 50, // Increase from default 20 depth: 10, // Increase from default 5 allowPrototypes: false // Prevent prototype pollution });

Problem solved: Query strings exceeding the default 1000 parameter limit resulted in silent data loss. The default allowPrototypes: true setting poses a prototype pollution security risk.

Implementation:

  • compileQueryParser now accepts optional qsOptions parameter
  • createExtendedQueryParser factory function replaces parseExtendedQueryString
  • app.set('query parser options') triggers parser recompilation
  • Does not affect 'simple' parser mode

Backward Compatibility

Both features maintain full backward compatibility:

  • Default behavior unchanged for both features
  • Works without setting new options
  • All existing tests pass (1269 total)

Test Coverage

  • CORS ETag tests: 13 new unit tests in test/utils.js + 10 integration tests in test/res.send.cors.js
  • Query parser tests: 11 new tests in test/req.query.options.js
  • Tests cover limits, security, edge cases, and backward compatibility

Security Considerations

The query parser feature helps prevent prototype pollution attacks by allowing developers to set allowPrototypes: false. The default remains true for backward compatibility, but documentation encourages the secure option.


iAn-P1nt0 avatar Nov 21 '25 08:11 iAn-P1nt0