Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3240d85

Browse files
alan-agius4kirjs
authored andcommitted
fix(http): prevent XSRF token leakage to protocol-relative URLs
The XSRF interceptor previously failed to detect protocol-relative URLs (starting with `//`) as absolute URLs. This allowed requests to such URLs to include the XSRF token, potentially leaking it to external domains. This change updates the interceptor to correctly identify protocol-relative URLs as absolute and exclude them from receiving the XSRF token. (cherry picked from commit 40790ef)
1 parent 908b5a4 commit 3240d85

File tree

2 files changed

+23
-3
lines changed

2 files changed

+23
-3
lines changed

‎packages/common/http/src/xsrf.ts‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,15 @@ export abstract class HttpXsrfTokenExtractor {
9191
abstract getToken(): string | null;
9292
}
9393

94+
/**
95+
* Regex to match absolute URLs, including protocol-relative URLs.
96+
*/
97+
const ABSOLUTE_URL_REGEX = /^(?:https?:)?\/\//i;
98+
9499
export function xsrfInterceptorFn(
95100
req: HttpRequest<unknown>,
96101
next: HttpHandlerFn,
97102
): Observable<HttpEvent<unknown>> {
98-
const lcUrl = req.url.toLowerCase();
99103
// Skip both non-mutating requests and absolute URLs.
100104
// Non-mutating requests don't require a token, and absolute URLs require special handling
101105
// anyway as the cookie set
@@ -104,8 +108,7 @@ export function xsrfInterceptorFn(
104108
!inject(XSRF_ENABLED) ||
105109
req.method === 'GET' ||
106110
req.method === 'HEAD' ||
107-
lcUrl.startsWith('http://') ||
108-
lcUrl.startsWith('https://')
111+
ABSOLUTE_URL_REGEX.test(req.url)
109112
) {
110113
return next(req);
111114
}

‎packages/common/http/test/xsrf_spec.ts‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,23 @@ describe('HttpXsrfInterceptor', () => {
7171
expect(req.request.headers.has('X-XSRF-TOKEN')).toEqual(false);
7272
req.flush({});
7373
});
74+
75+
it('does not apply XSRF protection when request is absolute', () => {
76+
interceptor
77+
.intercept(new HttpRequest('POST', 'https://example.com/test', {}), backend)
78+
.subscribe();
79+
const req = backend.expectOne('https://example.com/test');
80+
expect(req.request.headers.has('X-XSRF-TOKEN')).toBeFalse();
81+
req.flush({});
82+
});
83+
84+
it('does not apply XSRF protection when request is protocol relative', () => {
85+
interceptor.intercept(new HttpRequest('POST', '//example.com/test', {}), backend).subscribe();
86+
const req = backend.expectOne('//example.com/test');
87+
expect(req.request.headers.has('X-XSRF-TOKEN')).toBeFalse();
88+
req.flush({});
89+
});
90+
7491
it('does not overwrite existing header', () => {
7592
interceptor
7693
.intercept(

0 commit comments

Comments
 (0)