mirror of
https://github.com/Sea-Haven-Industries/sh-mcp.git
synced 2026-10-07 11:38:58 +00:00
Fix polynomial ReDoS in Bearer-token extraction (CodeQL js/polynomial-redos)
extractBearerToken matched /^Bearer\s+(.+)$/ — \s and . both match a space, so the two quantifiers overlap and a crafted header can drive polynomial backtracking. Require the capture to start with a non-whitespace char (/^Bearer\s+(\S.*)$/), removing the ambiguity → linear match. Behavior is unchanged for real tokens; +2 regression tests.
This commit is contained in:
parent
00762de0a6
commit
f4111e4e17
2 changed files with 15 additions and 1 deletions
|
|
@ -260,4 +260,14 @@ describe('extractBearerToken', () => {
|
||||||
it('throws AuthError on a non-Bearer header', () => {
|
it('throws AuthError on a non-Bearer header', () => {
|
||||||
expect(() => extractBearerToken('Basic abc')).toThrow(AuthError);
|
expect(() => extractBearerToken('Basic abc')).toThrow(AuthError);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ReDoS guard (CodeQL js/polynomial-redos): the matcher is /\s+(\S.*)/, not
|
||||||
|
// the ambiguous /\s+(.+)/. These pin the behavior that the `\S` fix preserves.
|
||||||
|
it('still captures a token that follows multiple separating spaces', () => {
|
||||||
|
expect(extractBearerToken('Bearer abc.def')).toBe('abc.def');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects a "Bearer" header with no token after the whitespace', () => {
|
||||||
|
expect(() => extractBearerToken(`Bearer ${' '.repeat(5_000)}`)).toThrow(AuthError);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,11 @@ export function extractBearerToken(req: unknown): string {
|
||||||
if (!header) {
|
if (!header) {
|
||||||
throw new AuthError('missing_token', 'No Authorization header present.');
|
throw new AuthError('missing_token', 'No Authorization header present.');
|
||||||
}
|
}
|
||||||
const match = /^Bearer\s+(.+)$/i.exec(header.trim());
|
// `\s+(\S.*)` — NOT `\s+(.+)`: requiring the capture to start with a
|
||||||
|
// non-whitespace char removes the quantifier overlap (both `\s` and `.`
|
||||||
|
// match a space), which otherwise allows polynomial backtracking on a
|
||||||
|
// crafted all-whitespace header (CodeQL js/polynomial-redos). Linear now.
|
||||||
|
const match = /^Bearer\s+(\S.*)$/i.exec(header.trim());
|
||||||
const token = match?.[1]?.trim();
|
const token = match?.[1]?.trim();
|
||||||
if (!token) {
|
if (!token) {
|
||||||
throw new AuthError('missing_token', 'Authorization header is not a Bearer token.');
|
throw new AuthError('missing_token', 'Authorization header is not a Bearer token.');
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue