Skip to content

Commit 743dbe3

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix(redaction): preserve workflow state tokens
1 parent 0111e54 commit 743dbe3

2 files changed

Lines changed: 60 additions & 2 deletions

File tree

apps/sim/lib/core/security/redaction.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ describe('isSensitiveKey', () => {
5353
expect(isSensitiveKey('refresh_token')).toBe(true)
5454
expect(isSensitiveKey('auth_token')).toBe(true)
5555
expect(isSensitiveKey('accessToken')).toBe(true)
56+
expect(isSensitiveKey('sessionToken')).toBe(true)
57+
expect(isSensitiveKey('webIdentityToken')).toBe(true)
58+
expect(isSensitiveKey('verificationToken')).toBe(true)
59+
expect(isSensitiveKey('githubToken')).toBe(true)
5660
})
5761

5862
it.concurrent('should match secret variations', () => {
@@ -110,6 +114,22 @@ describe('isSensitiveKey', () => {
110114
})
111115

112116
describe('non-sensitive keys (no false positives)', () => {
117+
it.concurrent('should preserve workflow-state tokens that do not grant access', () => {
118+
expect(isSensitiveKey('syncToken')).toBe(false)
119+
expect(isSensitiveKey('SyncToken')).toBe(false)
120+
expect(isSensitiveKey('nextSyncToken')).toBe(false)
121+
expect(isSensitiveKey('pageToken')).toBe(false)
122+
expect(isSensitiveKey('nextPageToken')).toBe(false)
123+
expect(isSensitiveKey('scroll_token')).toBe(false)
124+
expect(isSensitiveKey('continuationToken')).toBe(false)
125+
expect(isSensitiveKey('nextContinuationToken')).toBe(false)
126+
expect(isSensitiveKey('cursorToken')).toBe(false)
127+
expect(isSensitiveKey('nextToken')).toBe(false)
128+
expect(isSensitiveKey('clientRequestToken')).toBe(false)
129+
expect(isSensitiveKey('idempotencyToken')).toBe(false)
130+
expect(isSensitiveKey('subjectFromWebIdentityToken')).toBe(false)
131+
})
132+
113133
it.concurrent('should not match keys with sensitive words as prefix only', () => {
114134
expect(isSensitiveKey('tokenCount')).toBe(false)
115135
expect(isSensitiveKey('tokenizer')).toBe(false)
@@ -230,6 +250,32 @@ describe('redactApiKeys', () => {
230250
expect(result.config.normalField).toBe('normal-value')
231251
})
232252

253+
it.concurrent('should preserve non-secret token fields while redacting credentials', () => {
254+
const result = redactApiKeys({
255+
syncToken: '3',
256+
nextPageToken: 'page-2',
257+
nextToken: 'next-page',
258+
continuationToken: 'continue-page',
259+
clientRequestToken: 'idempotency-key',
260+
record: { Id: '42', SyncToken: '3' },
261+
accessToken: 'access-secret',
262+
sessionToken: 'session-secret',
263+
verificationToken: 'verification-secret',
264+
})
265+
266+
expect(result).toEqual({
267+
syncToken: '3',
268+
nextPageToken: 'page-2',
269+
nextToken: 'next-page',
270+
continuationToken: 'continue-page',
271+
clientRequestToken: 'idempotency-key',
272+
record: { Id: '42', SyncToken: '3' },
273+
accessToken: REDACTED_MARKER,
274+
sessionToken: REDACTED_MARKER,
275+
verificationToken: REDACTED_MARKER,
276+
})
277+
})
278+
233279
it.concurrent('should redact sensitive keys in arrays', () => {
234280
const arr = [{ apiKey: 'secret-key-1' }, { apiKey: 'secret-key-2' }]
235281

apps/sim/lib/core/security/redaction.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,19 @@ import { filterUserFileForDisplay, isUserFile } from '@/lib/core/utils/user-file
77
export const REDACTED_MARKER = '[REDACTED]'
88
export const TRUNCATED_MARKER = '[TRUNCATED]'
99

10-
const BYPASS_REDACTION_KEYS = new Set(['nextPageToken'])
10+
/**
11+
* Token-named fields that carry workflow state rather than authorization.
12+
*
13+
* Keep this allowlist semantic and narrow: unknown `*token` fields remain
14+
* redacted by default, while pagination cursors, synchronization versions, and
15+
* idempotency keys stay visible so users can pass them into subsequent steps.
16+
*/
17+
const NON_SENSITIVE_TOKEN_KEY_PATTERNS: RegExp[] = [
18+
/(?:page|pagination|continuation|cursor|scroll|sync)[_-]?token$/i,
19+
/^(?:next|previous|after|before)[_-]?token$/i,
20+
/^(?:client[_-]?request|idempotency)[_-]?token$/i,
21+
/^subjectFromWebIdentityToken$/i,
22+
]
1123

1224
/** Keys that contain large binary/encoded data that should be truncated in logs */
1325
const LARGE_DATA_KEYS = new Set(['base64'])
@@ -74,7 +86,7 @@ const SENSITIVE_VALUE_PATTERNS: Array<{
7486
]
7587

7688
export function isSensitiveKey(key: string): boolean {
77-
if (BYPASS_REDACTION_KEYS.has(key)) {
89+
if (NON_SENSITIVE_TOKEN_KEY_PATTERNS.some((pattern) => pattern.test(key))) {
7890
return false
7991
}
8092
const lowerKey = key.toLowerCase()

0 commit comments

Comments
 (0)