From b663ab9dd698704ae42f6fc2774b502c76a1eae9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 9 Sep 2026 14:49:44 +0000 Subject: [PATCH] test: add unit tests for SchemaReader.validateContentType Adds direct unit test coverage for validateContentType, the SSRF Content-Type allow-list check used when reading remote schemas. Previously this security-relevant function had no dedicated tests. Covers: allowed schema media types (json/yaml variants, text/plain, octet-stream), charset-parameter stripping, case-insensitive comparison, null Content-Type handling, rejection of non-schema types (text/html, image/png), and full bypass when SSRF protection is disabled. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../SsrfSecurityTests.fs | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/tests/SwaggerProvider.Tests/SsrfSecurityTests.fs b/tests/SwaggerProvider.Tests/SsrfSecurityTests.fs index ae9d10b4..47bf01d3 100644 --- a/tests/SwaggerProvider.Tests/SsrfSecurityTests.fs +++ b/tests/SwaggerProvider.Tests/SsrfSecurityTests.fs @@ -352,3 +352,70 @@ module SsrfBypassTests = | ex when ex.Message.Contains("Only HTTPS") -> Assert.True(false, $"HTTP should not be rejected by SSRF validation when disabled: {ex.Message}") | _ -> () + +/// Tests for validateContentType - Critical: SSRF protection via Content-Type validation. +/// Prevents processing of non-schema responses (HTML, images, binaries) that an attacker-controlled +/// endpoint could return in an SSRF attempt. Previously had no direct unit test coverage. +module ContentTypeValidationTests = + open System.Net.Http.Headers + + [] + let ``Allow application/json when SSRF protection is enabled``() = + let contentType = MediaTypeHeaderValue("application/json") + validateContentType false contentType + + [] + [] + [] + [] + [] + [] + [] + let ``Allow known schema Content-Types when SSRF protection is enabled``(mediaType: string) = + let contentType = MediaTypeHeaderValue(mediaType) + validateContentType false contentType + + [] + let ``Allow Content-Type with charset parameter``() = + // e.g. "application/json; charset=utf-8" — parameters must be stripped before comparison + let contentType = MediaTypeHeaderValue("application/json") + contentType.CharSet <- "utf-8" + validateContentType false contentType + + [] + let ``Reject text/html Content-Type when SSRF protection is enabled``() = + let contentType = MediaTypeHeaderValue("text/html") + + let thrown = + Assert.Throws(fun () -> validateContentType false contentType) + + Assert.Contains("Invalid Content-Type", thrown.Message) + + [] + let ``Reject image Content-Type when SSRF protection is enabled``() = + let contentType = MediaTypeHeaderValue("image/png") + + let thrown = + Assert.Throws(fun () -> validateContentType false contentType) + + Assert.Contains("Invalid Content-Type", thrown.Message) + + [] + let ``Content-Type comparison is case-insensitive``() = + let contentType = MediaTypeHeaderValue("APPLICATION/JSON") + validateContentType false contentType + + [] + let ``Allow null Content-Type when SSRF protection is enabled``() = + // Some servers omit Content-Type entirely; validation should not fail in this case. + validateContentType false null + + [] + let ``Allow any Content-Type when SSRF protection is disabled``() = + let contentType = MediaTypeHeaderValue("text/html") + // Should not throw when ignoreSsrfProtection=true (development mode) + validateContentType true contentType + + [] + let ``Allow null Content-Type when SSRF protection is disabled``() = + validateContentType true null