Skip to content

Commit b02dad9

Browse files
committed
fix: add production hardening for security and reliability
Security Fixes: - Add 10mb JSON body size limit to prevent DoS attacks - Validate EVM_ACCOUNT_INDEX to prevent NaN injection - Add HTTP server timeouts (120s request, 65s keepalive) Reliability Fixes: - Implement session cleanup (30min timeout, check every 5min) - Update session timestamps on activity to prevent premature cleanup - Prevent memory leaks from abandoned sessions These changes ensure the server is production-ready and resilient.
1 parent 07687b1 commit b02dad9

2 files changed

Lines changed: 38 additions & 3 deletions

File tree

src/core/services/wallet.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,15 @@ import { privateKeyToAccount, mnemonicToAccount, type HDAccount, type PrivateKey
1212
export const getConfiguredAccount = (): HDAccount | PrivateKeyAccount => {
1313
const privateKey = process.env.EVM_PRIVATE_KEY;
1414
const mnemonic = process.env.EVM_MNEMONIC;
15-
const accountIndex = parseInt(process.env.EVM_ACCOUNT_INDEX || '0');
15+
const accountIndexStr = process.env.EVM_ACCOUNT_INDEX || '0';
16+
const accountIndex = parseInt(accountIndexStr, 10);
17+
18+
// Validate account index
19+
if (isNaN(accountIndex) || accountIndex < 0 || !Number.isInteger(accountIndex)) {
20+
throw new Error(
21+
`Invalid EVM_ACCOUNT_INDEX: "${accountIndexStr}". Must be a non-negative integer.`
22+
);
23+
}
1624

1725
if (privateKey) {
1826
// Use private key if provided

src/server/http-server.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,30 @@ console.error(`Configured to listen on ${HOST}:${PORT}`);
1212

1313
// Setup Express
1414
const app = express();
15-
app.use(express.json());
15+
app.use(express.json({ limit: '10mb' })); // Prevent DoS attacks with huge payloads
1616

17-
// Track active transports by session ID
17+
// Track active transports by session ID with cleanup
1818
const transports = new Map<string, StreamableHTTPServerTransport>();
19+
const sessionTimestamps = new Map<string, number>();
20+
const SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
21+
22+
// Cleanup stale sessions periodically
23+
setInterval(() => {
24+
const now = Date.now();
25+
for (const [sessionId, timestamp] of sessionTimestamps.entries()) {
26+
if (now - timestamp > SESSION_TIMEOUT_MS) {
27+
console.error(`Cleaning up stale session: ${sessionId}`);
28+
const transport = transports.get(sessionId);
29+
if (transport) {
30+
transport.close().catch(err =>
31+
console.error(`Error closing stale session ${sessionId}:`, err)
32+
);
33+
}
34+
transports.delete(sessionId);
35+
sessionTimestamps.delete(sessionId);
36+
}
37+
}
38+
}, 5 * 60 * 1000); // Check every 5 minutes
1939

2040
// Initialize the MCP server
2141
let server: McpServer | null = null;
@@ -44,6 +64,7 @@ app.post("/mcp", async (req: Request, res: Response) => {
4464
if (sessionId && transports.has(sessionId)) {
4565
// Reuse existing transport for this session
4666
transport = transports.get(sessionId)!;
67+
sessionTimestamps.set(sessionId, Date.now()); // Update last activity
4768
console.error(`Reusing transport for session: ${sessionId}`);
4869
} else if (!sessionId) {
4970
// New session - create transport with session ID generator
@@ -52,10 +73,12 @@ app.post("/mcp", async (req: Request, res: Response) => {
5273
onsessioninitialized: (newSessionId) => {
5374
console.error(`Session initialized: ${newSessionId}`);
5475
transports.set(newSessionId, transport);
76+
sessionTimestamps.set(newSessionId, Date.now());
5577
},
5678
onsessionclosed: (closedSessionId) => {
5779
console.error(`Session closed: ${closedSessionId}`);
5880
transports.delete(closedSessionId);
81+
sessionTimestamps.delete(closedSessionId);
5982
}
6083
});
6184

@@ -191,3 +214,7 @@ const httpServer = app.listen(PORT, HOST, () => {
191214
console.error(`Server error: ${err}`);
192215
process.exit(1);
193216
});
217+
218+
// Set server timeout to prevent hanging connections
219+
httpServer.timeout = 120000; // 2 minutes
220+
httpServer.keepAliveTimeout = 65000; // 65 seconds

0 commit comments

Comments
 (0)