Skip to content

Commit 6793452

Browse files
authored
fix: Guard against invalid req.user input (getsentry#2512)
1 parent 1ed8a18 commit 6793452

File tree

4 files changed

+28
-13
lines changed

4 files changed

+28
-13
lines changed

packages/node/src/handlers.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Span } from '@sentry/apm';
22
import { captureException, getCurrentHub, withScope } from '@sentry/core';
33
import { Event } from '@sentry/types';
4-
import { forget, isString, logger, normalize } from '@sentry/utils';
4+
import { forget, isPlainObject, isString, logger, normalize } from '@sentry/utils';
55
import * as cookie from 'cookie';
66
import * as domain from 'domain';
77
import * as http from 'http';
@@ -256,7 +256,7 @@ export function parseRequest(
256256
}
257257

258258
if (options.user) {
259-
const extractedUser = req.user ? extractUserData(req.user, options.user) : {};
259+
const extractedUser = req.user && isPlainObject(req.user) ? extractUserData(req.user, options.user) : {};
260260

261261
if (Object.keys(extractedUser)) {
262262
event.user = {

packages/node/test/handlers.test.ts

+22-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import { Event } from '../src';
1+
import { Runtime } from '@sentry/types';
2+
3+
import { Event, Request, User } from '../src';
24
import { parseRequest } from '../src/handlers';
35

46
describe('parseRequest', () => {
@@ -21,12 +23,12 @@ describe('parseRequest', () => {
2123
describe('parseRequest.contexts runtime', () => {
2224
test('runtime name must contain node', () => {
2325
const parsedRequest: Event = parseRequest({}, mockReq);
24-
expect(parsedRequest.contexts.runtime.name).toEqual('node');
26+
expect((parsedRequest.contexts!.runtime as Runtime).name).toEqual('node');
2527
});
2628

2729
test('runtime version must contain current node version', () => {
2830
const parsedRequest: Event = parseRequest({}, mockReq);
29-
expect(parsedRequest.contexts.runtime.version).toEqual(process.version);
31+
expect((parsedRequest.contexts!.runtime as Runtime).version).toEqual(process.version);
3032
});
3133

3234
test('runtime disbaled by options', () => {
@@ -42,17 +44,27 @@ describe('parseRequest', () => {
4244
const CUSTOM_USER_KEYS = ['custom_property'];
4345

4446
test('parseRequest.user only contains the default properties from the user', () => {
45-
const parsedRequest: Event = parseRequest({}, mockReq, {
46-
user: DEFAULT_USER_KEYS,
47-
});
48-
expect(Object.keys(parsedRequest.user as any[])).toEqual(DEFAULT_USER_KEYS);
47+
const parsedRequest: Event = parseRequest({}, mockReq);
48+
expect(Object.keys(parsedRequest.user as User)).toEqual(DEFAULT_USER_KEYS);
4949
});
5050

5151
test('parseRequest.user only contains the custom properties specified in the options.user array', () => {
5252
const parsedRequest: Event = parseRequest({}, mockReq, {
5353
user: CUSTOM_USER_KEYS,
5454
});
55-
expect(Object.keys(parsedRequest.user as any[])).toEqual(CUSTOM_USER_KEYS);
55+
expect(Object.keys(parsedRequest.user as User)).toEqual(CUSTOM_USER_KEYS);
56+
});
57+
58+
test('parseRequest.user doesnt blow up when someone passes non-object value', () => {
59+
const parsedRequest: Event = parseRequest(
60+
{},
61+
{
62+
...mockReq,
63+
// @ts-ignore
64+
user: 'wat',
65+
},
66+
);
67+
expect(Object.keys(parsedRequest.user as User)).toEqual([]);
5668
});
5769
});
5870

@@ -92,15 +104,15 @@ describe('parseRequest', () => {
92104
test('parseRequest.request only contains the default set of properties from the request', () => {
93105
const DEFAULT_REQUEST_PROPERTIES = ['cookies', 'data', 'headers', 'method', 'query_string', 'url'];
94106
const parsedRequest: Event = parseRequest({}, mockReq);
95-
expect(Object.keys(parsedRequest.request as {})).toEqual(DEFAULT_REQUEST_PROPERTIES);
107+
expect(Object.keys(parsedRequest.request as Request)).toEqual(DEFAULT_REQUEST_PROPERTIES);
96108
});
97109

98110
test('parseRequest.request only contains the specified properties in the options.request array', () => {
99111
const INCLUDED_PROPERTIES = ['data', 'headers', 'query_string', 'url'];
100112
const parsedRequest: Event = parseRequest({}, mockReq, {
101113
request: INCLUDED_PROPERTIES,
102114
});
103-
expect(Object.keys(parsedRequest.request as {})).toEqual(INCLUDED_PROPERTIES);
115+
expect(Object.keys(parsedRequest.request as Request)).toEqual(INCLUDED_PROPERTIES);
104116
});
105117

106118
test('parseRequest.request skips `body` property for GET and HEAD requests', () => {

packages/types/src/event.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ export interface Event {
3030
};
3131
stacktrace?: Stacktrace;
3232
breadcrumbs?: Breadcrumb[];
33-
contexts?: { [key: string]: object };
33+
contexts?: {
34+
[key: string]: object;
35+
};
3436
tags?: { [key: string]: string };
3537
extra?: { [key: string]: any };
3638
user?: User;

packages/types/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export { Options } from './options';
1313
export { Package } from './package';
1414
export { Request } from './request';
1515
export { Response } from './response';
16+
export { Runtime } from './runtime';
1617
export { Scope } from './scope';
1718
export { SdkInfo } from './sdkinfo';
1819
export { Severity } from './severity';

0 commit comments

Comments
 (0)