From 7cb5b3d275fc9490eb45a388f6f153dfdcc2e703 Mon Sep 17 00:00:00 2001 From: aiirvizionz Date: Sat, 18 Jul 2026 17:30:25 -0600 Subject: [PATCH] fix(slack): reject malformed event timestamps --- packages/bridges/slack/src/index.test.ts | 34 ++++++++++++++++++++++++ packages/bridges/slack/src/index.ts | 5 ++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/bridges/slack/src/index.test.ts b/packages/bridges/slack/src/index.test.ts index 84b5c19b..3756ca56 100644 --- a/packages/bridges/slack/src/index.test.ts +++ b/packages/bridges/slack/src/index.test.ts @@ -214,6 +214,40 @@ describe('bridge-slack adapter', () => { expect(socket.closed).toBe(true); }); + it('falls back to the current time for malformed Slack timestamps', async () => { + vi.useFakeTimers().setSystemTime(new Date('2026-05-22T12:00:00.000Z')); + const fetchMock = vi.fn(async () => new Response(JSON.stringify({ + ok: true, + url: 'wss://slack.example/socket', + }), { status: 200 })); + vi.stubGlobal('fetch', fetchMock); + vi.stubGlobal('WebSocket', FakeSocket); + + const onMessage = vi.fn(); + await adapter.subscribe(subscribeCtx(), ['C-allowed'], onMessage, {}); + + await FakeSocket.instances[0]?.onmessage?.({ + data: JSON.stringify({ + envelope_id: 'env-bad-ts', + type: 'events_api', + payload: { + event: { + type: 'message', + channel: 'C-allowed', + user: 'U123', + text: 'bad timestamp', + event_ts: '.000200', + ts: '.000200', + }, + }, + }), + }); + + expect(onMessage).toHaveBeenCalledWith(expect.objectContaining({ + timestamp: '2026-05-22T12:00:00.000Z', + })); + }); + it('redacts Slack tokens from API errors', async () => { vi.stubGlobal('fetch', vi.fn(async () => new Response(JSON.stringify({ ok: false, diff --git a/packages/bridges/slack/src/index.ts b/packages/bridges/slack/src/index.ts index d95f29ad..e0277928 100644 --- a/packages/bridges/slack/src/index.ts +++ b/packages/bridges/slack/src/index.ts @@ -193,9 +193,10 @@ function renderUsername(msg: BridgeMessage): string { } function slackTimestamp(value: string): string { + if (!/^\d+(?:\.\d+)?$/.test(value)) return new Date().toISOString(); const seconds = Number(value.split('.')[0]); - if (!Number.isFinite(seconds)) return new Date().toISOString(); - return new Date(seconds * 1000).toISOString(); + const date = new Date(seconds * 1000); + return Number.isNaN(date.getTime()) ? new Date().toISOString() : date.toISOString(); } function websocketConstructor(): SlackWebSocketConstructor {