Skip to content

Commit bb2253d

Browse files
benmccannConduitrydominikg
authored
Merge pull request from GHSA-5p75-vc5g-8rv2
* fix: address security advisory CVE-2023-29003 by enabling CSRF protection for plain/text requests * Protect PUT/PATCH/DELETE. Add comment explicitly mentioning CSRF * update docs * update changeset * Update packages/kit/types/index.d.ts Co-authored-by: Conduitry <[email protected]> * Update packages/kit/types/index.d.ts * Update cool-lies-fly.md * Update packages/kit/src/utils/http.js Co-authored-by: Dominik G. <[email protected]> * Update packages/kit/types/index.d.ts Co-authored-by: Dominik G. <[email protected]> * test(csrf): include additional methods and content-types --------- Co-authored-by: Conduitry <[email protected]> Co-authored-by: Dominik G. <[email protected]>
1 parent 0e4b9b1 commit bb2253d

File tree

5 files changed

+42
-15
lines changed

5 files changed

+42
-15
lines changed

.changeset/cool-lies-fly.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
fix: address security advisory CVE-2023-29003 by including `text/plain` and `PUT`/`PATCH`/`DELETE` requests in set of blocked cross-origin requests for CSRF protection

packages/kit/src/runtime/server/respond.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,12 @@ export async function respond(request, options, manifest, state) {
5151

5252
if (options.csrf_check_origin) {
5353
const forbidden =
54-
request.method === 'POST' &&
55-
request.headers.get('origin') !== url.origin &&
56-
is_form_content_type(request);
54+
is_form_content_type(request) &&
55+
(request.method === 'POST' ||
56+
request.method === 'PUT' ||
57+
request.method === 'PATCH' ||
58+
request.method === 'DELETE') &&
59+
request.headers.get('origin') !== url.origin;
5760

5861
if (forbidden) {
5962
const csrf_error = error(403, `Cross-site ${request.method} form submissions are forbidden`);

packages/kit/src/utils/http.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,5 +68,12 @@ export function is_content_type(request, ...types) {
6868
* @param {Request} request
6969
*/
7070
export function is_form_content_type(request) {
71-
return is_content_type(request, 'application/x-www-form-urlencoded', 'multipart/form-data');
71+
// These content types must be protected against CSRF
72+
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/enctype
73+
return is_content_type(
74+
request,
75+
'application/x-www-form-urlencoded',
76+
'multipart/form-data',
77+
'text/plain'
78+
);
7279
}

packages/kit/test/apps/basics/test/server.test.js

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,27 @@ test.describe('Cookies', () => {
5858

5959
test.describe('CSRF', () => {
6060
test('Blocks requests with incorrect origin', async ({ baseURL }) => {
61-
const res = await fetch(`${baseURL}/csrf`, {
62-
method: 'POST',
63-
headers: {
64-
'content-type': 'application/x-www-form-urlencoded'
61+
const content_types = [
62+
'application/x-www-form-urlencoded',
63+
'multipart/form-data',
64+
'text/plain'
65+
];
66+
const methods = ['POST', 'PUT', 'PATCH', 'DELETE'];
67+
for (const method of methods) {
68+
for (const content_type of content_types) {
69+
const res = await fetch(`${baseURL}/csrf`, {
70+
method,
71+
headers: {
72+
'content-type': content_type
73+
}
74+
});
75+
const message = `request method: ${method}, content-type: ${content_type}`;
76+
expect(res.status, message).toBe(403);
77+
expect(await res.text(), message).toBe(
78+
`Cross-site ${method} form submissions are forbidden`
79+
);
6580
}
66-
});
67-
68-
expect(res.status).toBe(403);
69-
expect(await res.text()).toBe('Cross-site POST form submissions are forbidden');
81+
}
7082
});
7183
});
7284

packages/kit/types/index.d.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,13 +328,13 @@ export interface KitConfig {
328328
reportOnly?: CspDirectives;
329329
};
330330
/**
331-
* Protection against [cross-site request forgery](https://owasp.org/www-community/attacks/csrf) attacks.
331+
* Protection against [cross-site request forgery (CSRF)](https://owasp.org/www-community/attacks/csrf) attacks.
332332
*/
333333
csrf?: {
334334
/**
335-
* Whether to check the incoming `origin` header for `POST` form submissions and verify that it matches the server's origin.
335+
* Whether to check the incoming `origin` header for `POST`, `PUT`, `PATCH`, or `DELETE` form submissions and verify that it matches the server's origin.
336336
*
337-
* To allow people to make `POST` form submissions to your app from other origins, you will need to disable this option. Be careful!
337+
* To allow people to make `POST`, `PUT`, `PATCH`, or `DELETE` requests with a `Content-Type` of `application/x-www-form-urlencoded`, `multipart/form-data`, or `text/plain` to your app from other origins, you will need to disable this option. Be careful!
338338
* @default true
339339
*/
340340
checkOrigin?: boolean;

0 commit comments

Comments
 (0)