@@ -7,6 +7,24 @@ import { AppSystemProp, exceptionHandler } from 'workflow-server-shared'
7
7
import { apId , FileType , ProjectId } from 'workflow-shared'
8
8
import { system } from '../helper/system/system'
9
9
10
+ const ALLOWED_S3_ENDPOINTS = [
11
+ "https://s3.amazonaws.com" ,
12
+ "https://s3.us-east-1.amazonaws.com" ,
13
+ // Add other trusted endpoints as needed
14
+ ] ;
15
+
16
+ function isAllowedS3Endpoint ( url ?: string ) : boolean {
17
+ if ( ! url ) return true ; // Default AWS SDK endpoint if not set
18
+ try {
19
+ const parsed = new URL ( url ) ;
20
+ return ALLOWED_S3_ENDPOINTS . some ( allowed =>
21
+ parsed . origin === allowed
22
+ ) ;
23
+ } catch {
24
+ return false ;
25
+ }
26
+ }
27
+
10
28
export const s3Helper = ( log : FastifyBaseLogger ) => ( {
11
29
constructS3Key ( platformId : string | undefined , projectId : ProjectId | undefined , type : FileType , fileId : string ) : string {
12
30
const now = dayjs ( )
@@ -134,6 +152,11 @@ const getS3Client = () => {
134
152
const useIRSA = system . getBoolean ( AppSystemProp . S3_USE_IRSA )
135
153
const region = system . get < string > ( AppSystemProp . S3_REGION )
136
154
const endpoint = system . get < string > ( AppSystemProp . S3_ENDPOINT )
155
+
156
+ if ( ! isAllowedS3Endpoint ( endpoint ) ) {
157
+ throw new Error ( "Invalid or untrusted S3 endpoint. Only allow-listed endpoints are permitted." ) ;
158
+ }
159
+
137
160
const options : S3ClientConfig = {
138
161
region,
139
162
forcePathStyle : endpoint ? true : undefined ,
0 commit comments