Skip to content

Commit a6ece66

Browse files
committed
Content validation improved
1 parent f983e4e commit a6ece66

File tree

1 file changed

+35
-13
lines changed

1 file changed

+35
-13
lines changed

src/SwaggerProvider.DesignTime/Utils.fs

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,19 +68,41 @@ module SchemaReader =
6868
then
6969
failwithf "Cannot fetch schemas from localhost/loopback addresses: %s (set SsrfProtection=false for development)" host
7070

71-
let validateContentType(contentType: Headers.MediaTypeHeaderValue) =
72-
if not(isNull contentType) then
71+
let validateContentType (ignoreSsrfProtection: bool) (contentType: Headers.MediaTypeHeaderValue) =
72+
// Skip validation if SSRF protection is disabled
73+
if ignoreSsrfProtection || isNull contentType then
74+
()
75+
else
7376
let mediaType = contentType.MediaType.ToLowerInvariant()
7477

75-
if
76-
not(
77-
mediaType.Contains "json"
78-
|| mediaType.Contains "yaml"
79-
|| mediaType.Contains "text"
80-
|| mediaType.Contains "application/octet-stream"
81-
)
82-
then
83-
failwithf "Invalid Content-Type for schema: %s. Expected JSON or YAML." mediaType
78+
// Allow only Content-Types that are valid for OpenAPI/Swagger schema files
79+
// This prevents SSRF attacks where an attacker tries to make the provider
80+
// fetch and process non-schema files (HTML, images, binaries, etc.)
81+
let isValidSchemaContentType =
82+
// JSON formats
83+
mediaType = "application/json"
84+
|| mediaType = "application/json; charset=utf-8"
85+
|| mediaType.StartsWith "application/json;"
86+
// YAML formats
87+
|| mediaType = "application/yaml"
88+
|| mediaType = "application/x-yaml"
89+
|| mediaType = "text/yaml"
90+
|| mediaType = "text/x-yaml"
91+
|| mediaType.StartsWith "application/yaml;"
92+
|| mediaType.StartsWith "application/x-yaml;"
93+
|| mediaType.StartsWith "text/yaml;"
94+
|| mediaType.StartsWith "text/x-yaml;"
95+
// Plain text (sometimes used for YAML)
96+
|| mediaType = "text/plain"
97+
|| mediaType.StartsWith "text/plain;"
98+
// Generic binary (fallback for misconfigured servers)
99+
|| mediaType = "application/octet-stream"
100+
|| mediaType.StartsWith "application/octet-stream;"
101+
102+
if not isValidSchemaContentType then
103+
failwithf
104+
"Invalid Content-Type for schema: %s. Expected JSON or YAML content types only. This protects against SSRF attacks. Set SsrfProtection=false to disable this validation."
105+
mediaType
84106

85107
let readSchemaPath (ignoreSsrfProtection: bool) (headersStr: string) (schemaPathRaw: string) =
86108
async {
@@ -112,7 +134,7 @@ module SchemaReader =
112134
let! response = client.SendAsync request |> Async.AwaitTask
113135

114136
// Validate Content-Type to ensure we're parsing the correct format
115-
validateContentType response.Content.Headers.ContentType
137+
validateContentType ignoreSsrfProtection response.Content.Headers.ContentType
116138

117139
return! response.Content.ReadAsStringAsync() |> Async.AwaitTask
118140
}
@@ -171,7 +193,7 @@ module SchemaReader =
171193
let! response = client.SendAsync(request) |> Async.AwaitTask
172194

173195
// Validate Content-Type to ensure we're parsing the correct format
174-
validateContentType response.Content.Headers.ContentType
196+
validateContentType ignoreSsrfProtection response.Content.Headers.ContentType
175197

176198
return! response.Content.ReadAsStringAsync() |> Async.AwaitTask
177199
}

0 commit comments

Comments
 (0)