fix: increase max socket.io message size to 10MB for large pastes (#7474)

* fix: increase max socket.io message size to 10MB for large pastes

The default maxHttpBufferSize of 50KB caused socket.io to drop
connections when pasting >10,000 characters. Increased to 10MB which
safely accommodates large paste operations.

Fixes #4951

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: reduce default maxHttpBufferSize to 1MB

10MB was too generous and creates a DoS vector. 1MB (socket.io's own
default) is sufficient for large pastes while limiting memory abuse.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
John McLear 2026-04-06 15:12:08 +01:00 committed by GitHub
parent 2814e5b913
commit 29faec4a04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 73 additions and 16 deletions

View File

@ -64,9 +64,6 @@ jobs:
-
name: Write custom settings.json that enables the Admin UI tests
run: "sed -i 's/\"enableAdminUITests\": false/\"enableAdminUITests\": true,\\n\"users\":{\"admin\":{\"password\":\"changeme1\",\"is_admin\":true}}/' settings.json"
-
name: increase maxHttpBufferSize
run: "sed -i 's/\"maxHttpBufferSize\": 50000/\"maxHttpBufferSize\": 10000000/' settings.json"
-
name: Disable import/export rate limiting
run: |

View File

@ -574,13 +574,17 @@
"socketIo": {
/*
* Maximum permitted client message size (in bytes). All messages from
* clients that are larger than this will be rejected. Large values make it
* possible to paste large amounts of text, and plugins may require a larger
* value to work properly, but increasing the value increases susceptibility
* to denial of service attacks (malicious clients can exhaust memory).
* Maximum permitted client message size (in bytes). This controls the
* maximum single-message size for socket.io and directly affects large
* paste operations. All messages from clients that are larger than this
* will be rejected. Large values make it possible to paste large amounts
* of text, and plugins may require a larger value to work properly, but
* increasing the value increases susceptibility to denial of service
* attacks (malicious clients can exhaust memory).
*
* 1MB accommodates large pastes while still preventing abuse.
*/
"maxHttpBufferSize": "${SOCKETIO_MAX_HTTP_BUFFER_SIZE:50000}"
"maxHttpBufferSize": "${SOCKETIO_MAX_HTTP_BUFFER_SIZE:1000000}"
},
/*

View File

@ -573,13 +573,17 @@
"socketIo": {
/*
* Maximum permitted client message size (in bytes). All messages from
* clients that are larger than this will be rejected. Large values make it
* possible to paste large amounts of text, and plugins may require a larger
* value to work properly, but increasing the value increases susceptibility
* to denial of service attacks (malicious clients can exhaust memory).
* Maximum permitted client message size (in bytes). This controls the
* maximum single-message size for socket.io and directly affects large
* paste operations. All messages from clients that are larger than this
* will be rejected. Large values make it possible to paste large amounts
* of text, and plugins may require a larger value to work properly, but
* increasing the value increases susceptibility to denial of service
* attacks (malicious clients can exhaust memory).
*
* 1MB accommodates large pastes while still preventing abuse.
*/
"maxHttpBufferSize": 50000
"maxHttpBufferSize": 1000000
},
/*

View File

@ -366,7 +366,7 @@ const settings: SettingsType = {
* properly, but increasing the value increases susceptibility to denial of service attacks
* (malicious clients can exhaust memory).
*/
maxHttpBufferSize: 50000,
maxHttpBufferSize: 1000000,
},
/*
The authentication method used by the server.

View File

@ -0,0 +1,52 @@
'use strict';
const assert = require('assert').strict;
const common = require('../common');
let agent: any;
let apiVersion = 1;
describe(__filename, function () {
before(async function () {
agent = await common.init();
const res = await agent.get('/api/')
.expect(200)
.expect('Content-Type', /json/);
apiVersion = res.body.currentVersion;
assert(apiVersion);
});
it('can set and retrieve 50,000 characters of text on a pad', async function () {
this.timeout(30000);
const padId = `largePasteTest${Date.now()}`;
const largeText = 'A'.repeat(50000);
// Create the pad
let res = await agent.get(`/api/${apiVersion}/createPad?padID=${padId}`)
.set('Authorization', (await common.generateJWTToken()))
.expect(200)
.expect('Content-Type', /json/);
assert.equal(res.body.code, 0);
// Set large text
res = await agent.post(`/api/${apiVersion}/setText`)
.set('Authorization', (await common.generateJWTToken()))
.send({padID: padId, text: largeText})
.expect(200)
.expect('Content-Type', /json/);
assert.equal(res.body.code, 0);
// Retrieve and verify
res = await agent.get(`/api/${apiVersion}/getText?padID=${padId}`)
.set('Authorization', (await common.generateJWTToken()))
.expect(200)
.expect('Content-Type', /json/);
assert.equal(res.body.code, 0);
assert.equal(res.body.data.text, largeText + '\n');
// Clean up
await agent.get(`/api/${apiVersion}/deletePad?padID=${padId}`)
.set('Authorization', (await common.generateJWTToken()))
.expect(200);
});
});