Skip to content

Commit 858f7d2

Browse files
authored
fix(api-block): stop spoofing a browser fingerprint on outbound HTTP requests (#5496)
* fix(api-block): stop spoofing a browser fingerprint on outbound HTTP requests getDefaultHeaders() sent a Chrome User-Agent, a Referer pointing at Sim's own app, and mismatched Sec-Ch-Ua client hints on every API block request. Atlassian's Jira/Confluence Cloud REST API (and other browser-aware anti-CSRF/bot-defense layers) reject requests carrying a browser User-Agent with 403 "XSRF check failed", even with a valid Basic-auth header and X-Atlassian-Token: no-check set. Default headers now identify honestly as Sim, matching how other HTTP clients (curl, Postman, axios) behave. User-supplied headers still override any default. * fix(testing): sync shared tool-tester mock headers with new defaults createMockHeaders in the shared @sim/testing tool-tester builder still hardcoded the old Chrome UA / Referer / Sec-Ch-Ua fallback values. It was unreachable in current tests but would silently diverge from production getDefaultHeaders() for any future test hitting its fallback path.
1 parent 619e912 commit 858f7d2

3 files changed

Lines changed: 30 additions & 58 deletions

File tree

apps/sim/tools/http/request.test.ts

Lines changed: 21 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -119,28 +119,29 @@ describe('HTTP Request Tool', () => {
119119
expect(headers2['content-type']).toBe('text/plain')
120120
})
121121

122-
it('should set dynamic Referer header correctly', async () => {
123-
const originalWindow = global.window
124-
Object.defineProperty(global, 'window', {
125-
value: {
126-
location: {
127-
origin: 'https://sim.ai',
128-
},
129-
},
130-
writable: true,
122+
it('should not set a default Referer header', async () => {
123+
tester.setup(mockHttpResponses.simple)
124+
125+
await tester.execute({
126+
url: 'https://api.example.com',
127+
method: 'GET',
131128
})
132129

130+
const fetchCall = (global.fetch as any).mock.calls[0]
131+
expect(fetchCall[1].headers.Referer).toBeUndefined()
132+
})
133+
134+
it('should respect a user-provided Referer header', async () => {
133135
tester.setup(mockHttpResponses.simple)
134136

135137
await tester.execute({
136138
url: 'https://api.example.com',
137139
method: 'GET',
140+
headers: [{ cells: { Key: 'Referer', Value: 'https://custom.example.com' } }],
138141
})
139142

140143
const fetchCall = (global.fetch as any).mock.calls[0]
141-
expect(fetchCall[1].headers.Referer).toBe('https://sim.ai')
142-
143-
global.window = originalWindow
144+
expect(fetchCall[1].headers.Referer).toBe('https://custom.example.com')
144145
})
145146

146147
it('should set dynamic Host header correctly', async () => {
@@ -193,16 +194,6 @@ describe('HTTP Request Tool', () => {
193194
it('should apply default and dynamic headers to requests', async () => {
194195
tester.setup(mockHttpResponses.simple)
195196

196-
const originalWindow = global.window
197-
Object.defineProperty(global, 'window', {
198-
value: {
199-
location: {
200-
origin: 'https://sim.ai',
201-
},
202-
},
203-
writable: true,
204-
})
205-
206197
await tester.execute({
207198
url: 'https://api.example.com/data',
208199
method: 'GET',
@@ -212,15 +203,13 @@ describe('HTTP Request Tool', () => {
212203
const headers = fetchCall[1].headers
213204

214205
expect(headers.Host).toBe('api.example.com')
215-
expect(headers.Referer).toBe('https://sim.ai')
216-
expect(headers['User-Agent']).toContain('Mozilla')
206+
expect(headers.Referer).toBeUndefined()
207+
expect(headers['User-Agent']).toBe('Sim/1.0 (+https://sim.ai)')
217208
expect(headers.Accept).toBe('*/*')
218209
expect(headers['Accept-Encoding']).toContain('gzip')
219210
expect(headers['Cache-Control']).toBe('no-cache')
220211
expect(headers.Connection).toBe('keep-alive')
221-
expect(headers['Sec-Ch-Ua']).toContain('Chromium')
222-
223-
global.window = originalWindow
212+
expect(headers['Sec-Ch-Ua']).toBeUndefined()
224213
})
225214

226215
it('should handle successful GET requests', async () => {
@@ -434,16 +423,6 @@ describe('HTTP Request Tool', () => {
434423
it('should apply all default headers correctly', async () => {
435424
tester.setup(mockHttpResponses.simple)
436425

437-
const originalWindow = global.window
438-
Object.defineProperty(global, 'window', {
439-
value: {
440-
location: {
441-
origin: 'https://sim.ai',
442-
},
443-
},
444-
writable: true,
445-
})
446-
447426
await tester.execute({
448427
url: 'https://api.example.com/data',
449428
method: 'GET',
@@ -452,18 +431,16 @@ describe('HTTP Request Tool', () => {
452431
const fetchCall = (global.fetch as any).mock.calls[0]
453432
const headers = fetchCall[1].headers
454433

455-
expect(headers['User-Agent']).toMatch(/Mozilla\/5\.0.*Chrome.*Safari/)
434+
expect(headers['User-Agent']).toBe('Sim/1.0 (+https://sim.ai)')
456435
expect(headers.Accept).toBe('*/*')
457436
expect(headers['Accept-Encoding']).toBe('gzip, deflate, br')
458437
expect(headers['Cache-Control']).toBe('no-cache')
459438
expect(headers.Connection).toBe('keep-alive')
460-
expect(headers['Sec-Ch-Ua']).toMatch(/Chromium.*Not-A\.Brand/)
461-
expect(headers['Sec-Ch-Ua-Mobile']).toBe('?0')
462-
expect(headers['Sec-Ch-Ua-Platform']).toBe('"macOS"')
463-
expect(headers.Referer).toBe('https://sim.ai')
439+
expect(headers['Sec-Ch-Ua']).toBeUndefined()
440+
expect(headers['Sec-Ch-Ua-Mobile']).toBeUndefined()
441+
expect(headers['Sec-Ch-Ua-Platform']).toBeUndefined()
442+
expect(headers.Referer).toBeUndefined()
464443
expect(headers.Host).toBe('api.example.com')
465-
466-
global.window = originalWindow
467444
})
468445

469446
it('should allow overriding default headers', async () => {

apps/sim/tools/http/utils.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
import { getBaseUrl } from '@/lib/core/utils/urls'
21
import { transformTable } from '@/tools/shared/table'
32
import type { TableRow } from '@/tools/types'
43

54
/**
6-
* Creates a set of default headers used in HTTP requests
5+
* Creates a set of default headers used in HTTP requests.
6+
*
7+
* Identifies as Sim rather than impersonating a browser. Browser-fingerprint
8+
* headers (Referer, Sec-Ch-Ua*) trip anti-CSRF/bot-defense heuristics on
9+
* providers like Atlassian, which reject REST calls carrying a browser
10+
* User-Agent regardless of X-Atlassian-Token. See
11+
* https://support.atlassian.com/jira/kb/rest-api-calls-with-a-browser-user-agent-header-may-fail-csrf-checks/
712
* @param customHeaders Additional user-provided headers to include
813
* @param url Target URL for the request (used for setting Host header)
914
* @returns Record of HTTP headers
@@ -13,16 +18,11 @@ export const getDefaultHeaders = (
1318
url?: string
1419
): Record<string, string> => {
1520
const headers: Record<string, string> = {
16-
'User-Agent':
17-
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36',
21+
'User-Agent': 'Sim/1.0 (+https://sim.ai)',
1822
Accept: '*/*',
1923
'Accept-Encoding': 'gzip, deflate, br',
2024
'Cache-Control': 'no-cache',
2125
Connection: 'keep-alive',
22-
Referer: getBaseUrl(),
23-
'Sec-Ch-Ua': 'Chromium;v=91, Not-A.Brand;v=99',
24-
'Sec-Ch-Ua-Mobile': '?0',
25-
'Sec-Ch-Ua-Platform': '"macOS"',
2626
...customHeaders,
2727
}
2828

packages/testing/src/builders/tool-tester.builder.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,11 @@ export interface ToolResponse {
4343
*/
4444
const createMockHeaders = (customHeaders: Record<string, string> = {}) => {
4545
return {
46-
'User-Agent':
47-
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36',
46+
'User-Agent': 'Sim/1.0 (+https://sim.ai)',
4847
Accept: '*/*',
4948
'Accept-Encoding': 'gzip, deflate, br',
5049
'Cache-Control': 'no-cache',
5150
Connection: 'keep-alive',
52-
Referer: 'https://www.sim.ai',
53-
'Sec-Ch-Ua': 'Chromium;v=91, Not-A.Brand;v=99',
54-
'Sec-Ch-Ua-Mobile': '?0',
55-
'Sec-Ch-Ua-Platform': '"macOS"',
5651
...customHeaders,
5752
}
5853
}

0 commit comments

Comments
 (0)