Skip to content

Commit 0fd2c7f

Browse files
waleedlatif1claude
andcommitted
fix(data-drains): address PR review (signal in deliver, S3 endpoint SSRF, unused hook)
- webhook deliver: pass signal to secureFetchWithPinnedIP so aborts cancel the in-flight socket instead of waiting for the 30s timeout - S3 config: SSRF-validate the optional endpoint via validateExternalUrl so an enterprise admin cannot point the AWS SDK at internal/metadata addresses - hooks: remove unused useDataDrain (single-drain detail hook had no consumer) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 2f82488 commit 0fd2c7f

3 files changed

Lines changed: 15 additions & 24 deletions

File tree

apps/sim/ee/data-drains/hooks/data-drains.ts

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
type DataDrain,
88
type DataDrainRun,
99
deleteDataDrainContract,
10-
getDataDrainContract,
1110
listDataDrainRunsContract,
1211
listDataDrainsContract,
1312
runDataDrainContract,
@@ -36,18 +35,6 @@ async function fetchDataDrains(organizationId: string, signal?: AbortSignal): Pr
3635
return drains
3736
}
3837

39-
async function fetchDataDrain(
40-
organizationId: string,
41-
drainId: string,
42-
signal?: AbortSignal
43-
): Promise<DataDrain> {
44-
const { drain } = await requestJson(getDataDrainContract, {
45-
params: { id: organizationId, drainId },
46-
signal,
47-
})
48-
return drain
49-
}
50-
5138
async function fetchDataDrainRuns(
5239
organizationId: string,
5340
drainId: string,
@@ -72,15 +59,6 @@ export function useDataDrains(organizationId?: string) {
7259
})
7360
}
7461

75-
export function useDataDrain(organizationId?: string, drainId?: string) {
76-
return useQuery<DataDrain>({
77-
queryKey: dataDrainKeys.detail(drainId),
78-
queryFn: ({ signal }) => fetchDataDrain(organizationId as string, drainId as string, signal),
79-
enabled: Boolean(organizationId && drainId),
80-
staleTime: 60 * 1000,
81-
})
82-
}
83-
8462
export function useDataDrainRuns(organizationId?: string, drainId?: string, limit = 10) {
8563
return useQuery<DataDrainRun[]>({
8664
queryKey: [...dataDrainKeys.runs(drainId), limit] as const,

apps/sim/lib/data-drains/destinations/s3.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
import { createLogger } from '@sim/logger'
88
import { generateShortId } from '@sim/utils/id'
99
import { z } from 'zod'
10+
import { validateExternalUrl } from '@/lib/core/security/input-validation'
1011
import type { DrainDestination } from '@/lib/data-drains/types'
1112

1213
const logger = createLogger('DataDrainS3Destination')
@@ -16,8 +17,19 @@ const s3ConfigSchema = z.object({
1617
region: z.string().min(1, 'region is required').max(64),
1718
/** Optional prefix; trailing slash is added automatically when assembling keys. */
1819
prefix: z.string().max(512).optional(),
19-
/** Optional override for non-AWS S3-compatible providers (MinIO, R2, GCS interop, etc.). */
20-
endpoint: z.string().url().optional(),
20+
/**
21+
* Optional override for non-AWS S3-compatible providers (MinIO, R2, GCS interop, etc.).
22+
* SSRF-validated: HTTPS-only, must not resolve syntactically to a private,
23+
* loopback, or cloud-metadata address. The AWS SDK will issue requests to
24+
* this host, so we reject internal targets at the schema boundary.
25+
*/
26+
endpoint: z
27+
.string()
28+
.url()
29+
.refine((value) => validateExternalUrl(value, 'endpoint').isValid, {
30+
message: 'endpoint must be HTTPS and not point at a private, loopback, or metadata address',
31+
})
32+
.optional(),
2133
/**
2234
* Force path-style addressing. MinIO and Ceph RGW need `true`; AWS S3 and
2335
* Cloudflare R2 need `false`. No auto-default — explicit choice avoids

apps/sim/lib/data-drains/destinations/webhook.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ export const webhookDestination: DrainDestination<
211211
method: 'POST',
212212
body: new Uint8Array(body),
213213
headers,
214+
signal,
214215
timeout: PER_ATTEMPT_TIMEOUT_MS,
215216
})
216217
} catch (error) {

0 commit comments

Comments
 (0)