paygate-mcp 8.91.0 → 8.93.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.d.ts CHANGED
@@ -98,6 +98,8 @@ export declare class PayGateServer {
98
98
  readonly creditLedger: CreditLedger;
99
99
  /** Rate limiter for admin API endpoints (brute-force protection) */
100
100
  private readonly adminRateLimiter;
101
+ /** Rate limiter for session creation (prevents session slot exhaustion) */
102
+ private readonly sessionRateLimiter;
101
103
  /** Server start time (ms since epoch) */
102
104
  private readonly startedAt;
103
105
  /** Whether the server is draining (shutting down gracefully) */
@@ -380,6 +382,11 @@ export declare class PayGateServer {
380
382
  private syncKeyMutation;
381
383
  /** Resolve the CORS origin based on config and incoming request Origin header */
382
384
  private resolveCorsOrigin;
385
+ /**
386
+ * Check Content-Type is JSON. Returns true if valid, false and sends 415 if not.
387
+ * Exempt paths (like /oauth/token) accept form-urlencoded per RFC 6749.
388
+ */
389
+ private requireJsonContentType;
383
390
  private readBody;
384
391
  stop(): Promise<void>;
385
392
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/dist/server.js CHANGED
@@ -141,7 +141,9 @@ function clampArray(arr, maxLen) {
141
141
  * The full error is returned for internal logging only.
142
142
  */
143
143
  function safeErrorMessage(err, fallback = 'Invalid request') {
144
- const msg = err instanceof Error ? err.message : String(err);
144
+ const raw = err instanceof Error ? err.message : String(err);
145
+ // Truncate before regex matching to prevent ReDoS on crafted long strings
146
+ const msg = raw.slice(0, 500);
145
147
  // Allow known-safe, controlled error messages to pass through.
146
148
  // These are validation messages from our own code, not system/library errors.
147
149
  const safePatterns = [
@@ -177,6 +179,18 @@ function sanitizeString(value, maxLen = MAX_STRING_FIELD) {
177
179
  return '';
178
180
  return String(value).slice(0, maxLen);
179
181
  }
182
+ /**
183
+ * Sanitize a request URL for safe inclusion in log output.
184
+ * Strips control characters (newlines, tabs, carriage returns, etc.) that could
185
+ * be used for log injection attacks (forging log entries, hiding malicious activity).
186
+ * Truncates to 2048 chars to prevent log bloat from absurdly long URLs.
187
+ */
188
+ function sanitizeLogUrl(url) {
189
+ if (!url)
190
+ return '/';
191
+ // eslint-disable-next-line no-control-regex
192
+ return url.replace(/[\x00-\x1f\x7f]/g, '').slice(0, 2048);
193
+ }
180
194
  /** Clamp a numeric value to [min, max], returning defaultVal for NaN/undefined. */
181
195
  function clampInt(value, min, max, defaultVal) {
182
196
  if (value === undefined || !Number.isFinite(value))
@@ -306,6 +320,8 @@ class PayGateServer {
306
320
  creditLedger;
307
321
  /** Rate limiter for admin API endpoints (brute-force protection) */
308
322
  adminRateLimiter;
323
+ /** Rate limiter for session creation (prevents session slot exhaustion) */
324
+ sessionRateLimiter;
309
325
  /** Server start time (ms since epoch) */
310
326
  startedAt = Date.now();
311
327
  /** Whether the server is draining (shutting down gracefully) */
@@ -358,6 +374,8 @@ class PayGateServer {
358
374
  this.adminKeys.bootstrap(this.bootstrapAdminKey);
359
375
  // Admin endpoint rate limiter: configurable requests/min per source IP (brute-force protection)
360
376
  this.adminRateLimiter = new rate_limiter_1.RateLimiter(this.config.adminRateLimit ?? 120);
377
+ // Session creation rate limiter: max 60 new sessions/min per IP (prevents session slot exhaustion)
378
+ this.sessionRateLimiter = new rate_limiter_1.RateLimiter(this.config.sessionRateLimit ?? 60);
361
379
  this.gate = new gate_1.Gate(this.config, statePath);
362
380
  this.gate.store.logger = this.logger;
363
381
  // Multi-server mode: use Router
@@ -592,7 +610,7 @@ class PayGateServer {
592
610
  this.sendError(res, 408, 'Request timeout');
593
611
  }
594
612
  else {
595
- this.logger.error('Unhandled request error', { error: msg, url: req.url, method: req.method });
613
+ this.logger.error('Unhandled request error', { error: msg, url: sanitizeLogUrl(req.url), method: req.method });
596
614
  this.sendError(res, 500, 'Internal server error');
597
615
  }
598
616
  }
@@ -601,6 +619,7 @@ class PayGateServer {
601
619
  this.server.requestTimeout = this.config.requestTimeoutMs ?? 30_000; // 30s max per request (Node default: 0 = none)
602
620
  this.server.headersTimeout = this.config.headersTimeoutMs ?? 10_000; // 10s to receive headers (Node default: 60s)
603
621
  this.server.keepAliveTimeout = this.config.keepAliveTimeoutMs ?? 65_000; // 65s keep-alive (> typical 60s LB idle)
622
+ this.server.maxConnections = this.config.maxConnections ?? 10_000; // Cap concurrent TCP connections to prevent FD exhaustion
604
623
  if (this.config.maxRequestsPerSocket) {
605
624
  this.server.maxRequestsPerSocket = this.config.maxRequestsPerSocket; // Limit pipelined requests per socket
606
625
  }
@@ -750,7 +769,8 @@ class PayGateServer {
750
769
  return this.handleCreateKey(req, res);
751
770
  if (req.method === 'GET')
752
771
  return this.handleListKeys(req, res);
753
- break;
772
+ this.sendError(res, 405, 'Method not allowed. Use GET or POST.');
773
+ return;
754
774
  case '/keys/revoke':
755
775
  return this.handleRevokeKey(req, res);
756
776
  case '/keys/suspend':
@@ -845,7 +865,8 @@ class PayGateServer {
845
865
  return this.handleListTemplates(req, res);
846
866
  if (req.method === 'POST')
847
867
  return this.handleCreateTemplate(req, res);
848
- break;
868
+ this.sendError(res, 405, 'Method not allowed. Use GET or POST.');
869
+ return;
849
870
  case '/keys/templates/delete':
850
871
  return this.handleDeleteTemplate(req, res);
851
872
  case '/topup':
@@ -918,14 +939,16 @@ class PayGateServer {
918
939
  return this.handleGetAlerts(req, res);
919
940
  if (req.method === 'POST')
920
941
  return this.handleConfigureAlerts(req, res);
921
- break;
942
+ this.sendError(res, 405, 'Method not allowed. Use GET or POST.');
943
+ return;
922
944
  // ─── Webhook admin endpoints ─────────────────────────────────────
923
945
  case '/webhooks/dead-letter':
924
946
  if (req.method === 'GET')
925
947
  return this.handleGetDeadLetters(req, res);
926
948
  if (req.method === 'DELETE')
927
949
  return this.handleClearDeadLetters(req, res);
928
- break;
950
+ this.sendError(res, 405, 'Method not allowed. Use GET or DELETE.');
951
+ return;
929
952
  case '/webhooks/replay':
930
953
  return this.handleWebhookReplay(req, res);
931
954
  case '/webhooks/stats':
@@ -943,7 +966,8 @@ class PayGateServer {
943
966
  return this.handleListWebhookFilters(req, res);
944
967
  if (req.method === 'POST')
945
968
  return this.handleCreateWebhookFilter(req, res);
946
- break;
969
+ this.sendError(res, 405, 'Method not allowed. Use GET or POST.');
970
+ return;
947
971
  case '/webhooks/filters/update':
948
972
  return this.handleUpdateWebhookFilter(req, res);
949
973
  case '/webhooks/filters/delete':
@@ -954,7 +978,8 @@ class PayGateServer {
954
978
  return this.handleListTeams(req, res);
955
979
  if (req.method === 'POST')
956
980
  return this.handleCreateTeam(req, res);
957
- break;
981
+ this.sendError(res, 405, 'Method not allowed. Use GET or POST.');
982
+ return;
958
983
  case '/teams/update':
959
984
  return this.handleUpdateTeam(req, res);
960
985
  case '/teams/delete':
@@ -972,7 +997,8 @@ class PayGateServer {
972
997
  case '/tokens':
973
998
  if (req.method === 'POST')
974
999
  return this.handleCreateToken(req, res);
975
- break;
1000
+ this.sendError(res, 405, 'Method not allowed. Use POST.');
1001
+ return;
976
1002
  case '/tokens/revoke':
977
1003
  return this.handleRevokeToken(req, res);
978
1004
  case '/tokens/revoked':
@@ -983,7 +1009,8 @@ class PayGateServer {
983
1009
  return this.handleCreateAdminKey(req, res);
984
1010
  if (req.method === 'GET')
985
1011
  return this.handleListAdminKeys(req, res);
986
- break;
1012
+ this.sendError(res, 405, 'Method not allowed. Use GET or POST.');
1013
+ return;
987
1014
  case '/admin/keys/revoke':
988
1015
  return this.handleRevokeAdminKey(req, res);
989
1016
  case '/admin/keys/rotate-bootstrap':
@@ -1318,7 +1345,8 @@ class PayGateServer {
1318
1345
  return this.handleListGroups(req, res);
1319
1346
  if (req.method === 'POST')
1320
1347
  return this.handleCreateGroup(req, res);
1321
- break;
1348
+ this.sendError(res, 405, 'Method not allowed. Use GET or POST.');
1349
+ return;
1322
1350
  case '/groups/update':
1323
1351
  return this.handleUpdateGroup(req, res);
1324
1352
  case '/groups/delete':
@@ -1382,6 +1410,8 @@ class PayGateServer {
1382
1410
  this.sendError(res, 405, 'Method not allowed');
1383
1411
  return;
1384
1412
  }
1413
+ if (!this.requireJsonContentType(req, res))
1414
+ return;
1385
1415
  const body = await this.readBody(req);
1386
1416
  let request;
1387
1417
  try {
@@ -1418,6 +1448,15 @@ class PayGateServer {
1418
1448
  // Session management: reuse or create
1419
1449
  let sessionId = req.headers['mcp-session-id'];
1420
1450
  if (!sessionId || !this.sessions.getSession(sessionId)) {
1451
+ // Rate limit session creation per IP to prevent session slot exhaustion
1452
+ const sessionIp = resolveClientIp(req, this.config.trustedProxies);
1453
+ const sessionRateResult = this.sessionRateLimiter.check(`sess:${sessionIp}`);
1454
+ if (!sessionRateResult.allowed) {
1455
+ res.setHeader('Retry-After', String(Math.ceil(sessionRateResult.resetInMs / 1000)));
1456
+ this.sendError(res, 429, 'Too many sessions created. Try again later.');
1457
+ return;
1458
+ }
1459
+ this.sessionRateLimiter.record(`sess:${sessionIp}`);
1421
1460
  sessionId = this.sessions.createSession(apiKey);
1422
1461
  this.audit.log('session.created', (0, audit_1.maskKeyForAudit)(apiKey || 'anonymous'), `Session created`, {
1423
1462
  requestId,
@@ -1640,6 +1679,15 @@ class PayGateServer {
1640
1679
  // Session: reuse or create
1641
1680
  let sessionId = req.headers['mcp-session-id'];
1642
1681
  if (!sessionId || !this.sessions.getSession(sessionId)) {
1682
+ // Rate limit session creation per IP to prevent session slot exhaustion
1683
+ const sessionIp = resolveClientIp(req, this.config.trustedProxies);
1684
+ const sessionRateResult = this.sessionRateLimiter.check(`sess:${sessionIp}`);
1685
+ if (!sessionRateResult.allowed) {
1686
+ res.setHeader('Retry-After', String(Math.ceil(sessionRateResult.resetInMs / 1000)));
1687
+ this.sendError(res, 429, 'Too many sessions created. Try again later.');
1688
+ return;
1689
+ }
1690
+ this.sessionRateLimiter.record(`sess:${sessionIp}`);
1643
1691
  sessionId = this.sessions.createSession(apiKey);
1644
1692
  }
1645
1693
  // Register this SSE connection
@@ -1950,6 +1998,15 @@ class PayGateServer {
1950
1998
  const params = new URLSearchParams(urlParts[1] || '');
1951
1999
  const namespace = params.get('namespace') || undefined;
1952
2000
  const status = this.gate.getStatus(namespace);
2001
+ // Cap the keys array to prevent unbounded response sizes with many API keys.
2002
+ // The full paginated listing is available via GET /admin/keys.
2003
+ const MAX_STATUS_KEYS = 1000;
2004
+ if (status.keys && status.keys.length > MAX_STATUS_KEYS) {
2005
+ const totalKeys = status.keys.length;
2006
+ status.keys = status.keys.slice(0, MAX_STATUS_KEYS);
2007
+ status.keysTruncated = true;
2008
+ status.totalKeyCount = totalKeys;
2009
+ }
1953
2010
  res.writeHead(200, { 'Content-Type': 'application/json' });
1954
2011
  res.end(JSON.stringify(status, null, 2));
1955
2012
  }
@@ -4224,6 +4281,8 @@ class PayGateServer {
4224
4281
  this.sendError(res, 405, 'Method not allowed');
4225
4282
  return;
4226
4283
  }
4284
+ if (!this.requireJsonContentType(req, res))
4285
+ return;
4227
4286
  const body = await this.readBody(req);
4228
4287
  let params;
4229
4288
  try {
@@ -4360,13 +4419,15 @@ class PayGateServer {
4360
4419
  this.sendError(res, 405, 'Method not allowed');
4361
4420
  return;
4362
4421
  }
4422
+ if (!this.requireJsonContentType(req, res))
4423
+ return;
4363
4424
  const body = await this.readBody(req);
4364
4425
  let params;
4365
4426
  try {
4366
4427
  params = safeJsonParse(body);
4367
4428
  }
4368
4429
  catch {
4369
- // Try URL-encoded form data
4430
+ // Try URL-encoded form data (RFC 6749)
4370
4431
  params = {};
4371
4432
  const query = new URLSearchParams(body);
4372
4433
  for (const [k, v] of query)
@@ -4499,7 +4560,8 @@ class PayGateServer {
4499
4560
  const from = params.get('from') || undefined;
4500
4561
  const to = params.get('to') || undefined;
4501
4562
  const granularity = (params.get('granularity') || 'hourly');
4502
- const topN = params.get('top') ? parseInt(params.get('top'), 10) : 10;
4563
+ const topN = clampInt(params.get('top') ? parseInt(params.get('top'), 10) : undefined, 1, 1000, 10 // default 10, max 1000 — prevents memory exhaustion from ?top=999999999
4564
+ );
4503
4565
  const namespace = params.get('namespace') || undefined;
4504
4566
  const events = this.gate.meter.getEvents(undefined, namespace);
4505
4567
  const report = this.analytics.report(events, { from, to, granularity, topN });
@@ -10220,8 +10282,8 @@ class PayGateServer {
10220
10282
  this.adminRateLimiter.record(`ip:${sourceIp}`);
10221
10283
  const record = adminKey ? this.adminKeys.validate(adminKey) : null;
10222
10284
  if (!record) {
10223
- this.audit.log('admin.auth_failed', 'unknown', `Admin auth failed on ${req.url}`, {
10224
- url: req.url,
10285
+ this.audit.log('admin.auth_failed', 'unknown', `Admin auth failed on ${sanitizeLogUrl(req.url)}`, {
10286
+ url: sanitizeLogUrl(req.url),
10225
10287
  method: req.method,
10226
10288
  });
10227
10289
  this.sendError(res, 401, 'Invalid admin key');
@@ -10229,8 +10291,8 @@ class PayGateServer {
10229
10291
  }
10230
10292
  // Role-based permission check (if a minimum role is specified)
10231
10293
  if (minRole && admin_keys_1.ROLE_HIERARCHY[record.role] < admin_keys_1.ROLE_HIERARCHY[minRole]) {
10232
- this.audit.log('admin.auth_failed', adminKey.slice(0, 7) + '...' + adminKey.slice(-4), `Insufficient role for ${req.url} (need ${minRole}, have ${record.role})`, {
10233
- url: req.url,
10294
+ this.audit.log('admin.auth_failed', adminKey.slice(0, 7) + '...' + adminKey.slice(-4), `Insufficient role for ${sanitizeLogUrl(req.url)} (need ${minRole}, have ${record.role})`, {
10295
+ url: sanitizeLogUrl(req.url),
10234
10296
  method: req.method,
10235
10297
  requiredRole: minRole,
10236
10298
  currentRole: record.role,
@@ -10238,6 +10300,9 @@ class PayGateServer {
10238
10300
  this.sendError(res, 403, 'Insufficient permissions', { requiredRole: minRole, currentRole: record.role });
10239
10301
  return false;
10240
10302
  }
10303
+ // Content-Type enforcement for POST requests (after auth, before body read)
10304
+ if (req.method === 'POST' && !this.requireJsonContentType(req, res))
10305
+ return false;
10241
10306
  return true;
10242
10307
  }
10243
10308
  // ─── /teams — Team management ────────────────────────────────────────────
@@ -11060,6 +11125,28 @@ class PayGateServer {
11060
11125
  }
11061
11126
  return '*';
11062
11127
  }
11128
+ /**
11129
+ * Check Content-Type is JSON. Returns true if valid, false and sends 415 if not.
11130
+ * Exempt paths (like /oauth/token) accept form-urlencoded per RFC 6749.
11131
+ */
11132
+ requireJsonContentType(req, res) {
11133
+ if (req.method !== 'POST')
11134
+ return true; // Only enforce for POST
11135
+ const ct = (req.headers['content-type'] || '').toLowerCase();
11136
+ const url = req.url?.split('?')[0] || '/';
11137
+ if (url === '/oauth/token') {
11138
+ // OAuth token endpoint accepts both JSON and form-encoded per RFC 6749
11139
+ if (ct.startsWith('application/json') || ct.startsWith('application/x-www-form-urlencoded'))
11140
+ return true;
11141
+ this.sendError(res, 415, 'Unsupported Media Type. Use application/json or application/x-www-form-urlencoded');
11142
+ return false;
11143
+ }
11144
+ if (!ct.startsWith('application/json')) {
11145
+ this.sendError(res, 415, 'Unsupported Media Type. Use application/json');
11146
+ return false;
11147
+ }
11148
+ return true;
11149
+ }
11063
11150
  readBody(req) {
11064
11151
  return new Promise((resolve, reject) => {
11065
11152
  let body = '';
@@ -11217,6 +11304,7 @@ class PayGateServer {
11217
11304
  this.tokens.destroy();
11218
11305
  this.expiryScanner.destroy();
11219
11306
  this.adminRateLimiter.destroy();
11307
+ this.sessionRateLimiter.destroy();
11220
11308
  if (this.redisSync) {
11221
11309
  await this.redisSync.destroy();
11222
11310
  }