Skip to content

Commit c8c4867

Browse files
committed
fix(providers): fail closed when Azure endpoint validates without a pinnable IP
1 parent f405b37 commit c8c4867

4 files changed

Lines changed: 34 additions & 2 deletions

File tree

apps/sim/providers/azure-anthropic/index.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,17 @@ describe('azureAnthropicProvider — SSRF pinning', () => {
104104
expect(mockCreatePinnedFetch).not.toHaveBeenCalled()
105105
expect(mockExecuteAnthropic).not.toHaveBeenCalled()
106106
})
107+
108+
it('fails closed when validation passes but yields no resolvable IP to pin', async () => {
109+
mockValidate.mockResolvedValue({ isValid: true })
110+
111+
await expect(
112+
azureAnthropicProvider.executeRequest(
113+
request({ azureEndpoint: 'https://rebind.attacker.tld' })
114+
)
115+
).rejects.toThrow('could not resolve a pinnable IP address')
116+
117+
expect(mockCreatePinnedFetch).not.toHaveBeenCalled()
118+
expect(mockExecuteAnthropic).not.toHaveBeenCalled()
119+
})
107120
})

apps/sim/providers/azure-anthropic/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,12 @@ export const azureAnthropicProvider: ProviderConfig = {
3838
})
3939
throw new Error(`Invalid Azure Anthropic endpoint: ${validation.error}`)
4040
}
41+
if (!validation.resolvedIP) {
42+
throw new Error('Invalid Azure Anthropic endpoint: could not resolve a pinnable IP address')
43+
}
4144
// Pin the connection to the validated IP so the SDK's own DNS resolution at
4245
// connect time cannot be rebound to an internal address (TOCTOU SSRF).
43-
pinnedFetch = createPinnedFetch(validation.resolvedIP!)
46+
pinnedFetch = createPinnedFetch(validation.resolvedIP)
4447
}
4548

4649
const apiKey = request.apiKey

apps/sim/providers/azure-openai/index.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,19 @@ describe('azureOpenAIProvider — SSRF pinning', () => {
138138
expect(mockCreatePinnedFetch).not.toHaveBeenCalled()
139139
expect(mockExecuteResponses).not.toHaveBeenCalled()
140140
})
141+
142+
it('fails closed when validation passes but yields no resolvable IP to pin', async () => {
143+
mockValidate.mockResolvedValue({ isValid: true })
144+
145+
await expect(
146+
azureOpenAIProvider.executeRequest(
147+
request({ azureEndpoint: 'https://rebind.attacker.tld' })
148+
)
149+
).rejects.toThrow('could not resolve a pinnable IP address')
150+
151+
expect(mockCreatePinnedFetch).not.toHaveBeenCalled()
152+
expect(mockExecuteResponses).not.toHaveBeenCalled()
153+
})
141154
})
142155

143156
describe('Chat Completions path', () => {

apps/sim/providers/azure-openai/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -618,9 +618,12 @@ export const azureOpenAIProvider: ProviderConfig = {
618618
})
619619
throw new Error(`Invalid Azure OpenAI endpoint: ${validation.error}`)
620620
}
621+
if (!validation.resolvedIP) {
622+
throw new Error('Invalid Azure OpenAI endpoint: could not resolve a pinnable IP address')
623+
}
621624
// Pin the connection to the validated IP so the SDK / fetch DNS resolution
622625
// at connect time cannot be rebound to an internal address (TOCTOU SSRF).
623-
pinnedFetch = createPinnedFetch(validation.resolvedIP!)
626+
pinnedFetch = createPinnedFetch(validation.resolvedIP)
624627
}
625628

626629
const apiKey = request.apiKey

0 commit comments

Comments
 (0)