Skip to content

Commit b36f146

Browse files
committed
fix(http): ensure query parameters are inserted before URL fragments
Previously, when making an HTTP request where the URL contained a fragment (`#`) and `HttpParams` were provided, the parameters were appended to the very end of the URL (after the fragment). This resulted in the parameters being treated as part of the fragment rather than query parameters, potentially bypassing server-side logic and validation. This commit updates the URL parsing logic in `HttpRequest` to split the URL by the fragment, correctly inserting the query string before any fragment.
1 parent 6bde84f commit b36f146

2 files changed

Lines changed: 20 additions & 3 deletions

File tree

packages/common/http/src/request.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -408,17 +408,29 @@ export class HttpRequest<T> implements HttpRequestOptions {
408408
// No parameters, the visible URL is just the URL given at creation time.
409409
this.urlWithParams = url;
410410
} else {
411+
// Strip the fragment (e.g. #bypass) from the URL before checking for existing query parameters.
412+
// This ensures that new query parameters are inserted before the fragment, preventing
413+
// situations where parameters are mistakenly appended after the fragment and thus
414+
// only exposed to the frontend, which could bypass security checks.
415+
let urlWithoutFragment = url;
416+
let fragment = '';
417+
const hashIdx = url.indexOf('#');
418+
if (hashIdx !== -1) {
419+
fragment = url.substring(hashIdx);
420+
urlWithoutFragment = url.substring(0, hashIdx);
421+
}
422+
411423
// Does the URL already have query parameters? Look for '?'.
412-
const qIdx = url.indexOf('?');
424+
const qIdx = urlWithoutFragment.indexOf('?');
413425
// There are 3 cases to handle:
414426
// 1) No existing parameters -> append '?' followed by params.
415427
// 2) '?' exists and is followed by existing query string ->
416428
// append '&' followed by params.
417429
// 3) '?' exists at the end of the url -> append params directly.
418430
// This basically amounts to determining the character, if any, with
419431
// which to join the URL and parameters.
420-
const sep: string = qIdx === -1 ? '?' : qIdx < url.length - 1 ? '&' : '';
421-
this.urlWithParams = url + sep + params;
432+
const sep: string = qIdx === -1 ? '?' : qIdx < urlWithoutFragment.length - 1 ? '&' : '';
433+
this.urlWithParams = urlWithoutFragment + sep + params + fragment;
422434
}
423435
}
424436
}

packages/common/http/test/request_spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,5 +286,10 @@ describe('HttpRequest', () => {
286286
const req = baseReq.clone({setParams: {'test': 'false'}});
287287
expect(req.urlWithParams).toEqual('/test?test=false');
288288
});
289+
it('appends parameters before a fragment', () => {
290+
const fragmentParams = new HttpParams({fromString: 'auth_token=secret'});
291+
const req = baseReq.clone({params: fragmentParams, url: '/api/data/123#bypass'});
292+
expect(req.urlWithParams).toEqual('/api/data/123?auth_token=secret#bypass');
293+
});
289294
});
290295
});

0 commit comments

Comments
 (0)