fix(security): critical security and stability fixes
Some checks failed
Default (tags) / security (push) Successful in 1m2s
Default (tags) / test (push) Failing after 46m14s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped

This commit is contained in:
2025-08-14 14:30:54 +00:00
parent 6eac957baf
commit 5fbcf81c2c
19 changed files with 1647 additions and 1301 deletions

View File

@@ -22,6 +22,7 @@ import * as plugins from '../../../plugins.js';
import type { IRouteConfig, IRouteMatch, IRouteAction, IRouteTarget, TPortRange, IRouteContext } from '../models/route-types.js';
import { mergeRouteConfigs } from './route-utils.js';
import { ProtocolDetector, HttpDetector } from '../../../detection/index.js';
import { createSocketTracker } from '../../../core/utils/socket-tracker.js';
/**
* Create an HTTP-only route configuration
@@ -960,11 +961,12 @@ export const SocketHandlers = {
* Now uses the centralized detection module for HTTP parsing
*/
httpRedirect: (locationTemplate: string, statusCode: number = 301) => (socket: plugins.net.Socket, context: IRouteContext) => {
const tracker = createSocketTracker(socket);
const connectionId = ProtocolDetector.createConnectionId({
socketId: context.connectionId || `${Date.now()}-${Math.random()}`
});
socket.once('data', async (data) => {
const handleData = async (data: Buffer) => {
// Use detection module for parsing
const detectionResult = await ProtocolDetector.detectWithConnectionTracking(
data,
@@ -1005,6 +1007,19 @@ export const SocketHandlers = {
socket.end();
// Clean up detection state
ProtocolDetector.cleanupConnections();
// Clean up all tracked resources
tracker.cleanup();
};
// Use tracker to manage the listener
socket.once('data', handleData);
tracker.addListener('error', (err) => {
tracker.safeDestroy(err);
});
tracker.addListener('close', () => {
tracker.cleanup();
});
},
@@ -1013,7 +1028,9 @@ export const SocketHandlers = {
* Now uses the centralized detection module for HTTP parsing
*/
httpServer: (handler: (req: { method: string; url: string; headers: Record<string, string>; body?: string }, res: { status: (code: number) => void; header: (name: string, value: string) => void; send: (data: string) => void; end: () => void }) => void) => (socket: plugins.net.Socket, context: IRouteContext) => {
const tracker = createSocketTracker(socket);
let requestParsed = false;
let responseTimer: NodeJS.Timeout | null = null;
const connectionId = ProtocolDetector.createConnectionId({
socketId: context.connectionId || `${Date.now()}-${Math.random()}`
});
@@ -1034,6 +1051,8 @@ export const SocketHandlers = {
}
requestParsed = true;
// Remove data listener after parsing request
socket.removeListener('data', processData);
const connInfo = detectionResult.connectionInfo;
// Create request object from detection result
@@ -1060,6 +1079,12 @@ export const SocketHandlers = {
if (ended) return;
ended = true;
// Clear response timer since we're sending now
if (responseTimer) {
clearTimeout(responseTimer);
responseTimer = null;
}
if (!responseHeaders['content-type']) {
responseHeaders['content-type'] = 'text/plain';
}
@@ -1091,30 +1116,44 @@ export const SocketHandlers = {
try {
handler(req, res);
// Ensure response is sent even if handler doesn't call send()
setTimeout(() => {
responseTimer = setTimeout(() => {
if (!ended) {
res.send('');
}
responseTimer = null;
}, 1000);
// Track and unref the timer
tracker.addTimer(responseTimer);
} catch (error) {
if (!ended) {
res.status(500);
res.send('Internal Server Error');
}
// Use safeDestroy for error cases
tracker.safeDestroy(error instanceof Error ? error : new Error('Handler error'));
}
};
socket.on('data', processData);
// Use tracker to manage listeners
tracker.addListener('data', processData);
socket.on('error', () => {
tracker.addListener('error', (err) => {
if (!requestParsed) {
socket.end();
tracker.safeDestroy(err);
}
});
socket.on('close', () => {
tracker.addListener('close', () => {
// Cleanup is handled by tracker
// Clear any pending response timer
if (responseTimer) {
clearTimeout(responseTimer);
responseTimer = null;
}
// Clean up detection state
ProtocolDetector.cleanupConnections();
// Clean up all tracked resources
tracker.cleanup();
});
}
};