Skip to content

[compliance] Compliance Gap: Custom Schema URLs MUST be HTTPS Only (Section 4.1.4) #1391

@github-actions

Description

@github-actions

MCP Gateway Compliance Review — 2026-02-25

Summary

Found 1 critical compliance issue during daily review of commit 387f45d (Refactor: split mcp/connection.go by concern, relocate misplaced server helpers #1373).

Recent Changes Reviewed

  • internal/mcp/connection.go — split into connection.go + http_transport.go (refactor only)
  • internal/server/transport.goapplyAuthIfConfigured moved to auth.go, withResponseLogging moved to http_helpers.go
  • Commit reviewed: 387f45d3dbcb2c917a56501047a633eaf981605f

The refactor itself is clean — no behavioral regressions detected. However, the review surfaced a pre-existing MUST violation in custom schema URL validation.


Critical Issues (MUST violations)

Issue 1: Custom Schema URLs Not Validated to be HTTPS-Only

Specification Section: 4.1.4 Custom Server Types
Deep Link: https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/mcp-gateway.md#414-custom-server-types

Requirement:

"Custom schema URLs MUST be HTTPS URLs only (for security reasons)"

Current State:

The validateCustomSchemas function in internal/config/validation.go (lines 316–333) validates only that custom type names do not conflict with reserved types ("stdio", "http"). It does not validate that the schema URL starts with https://.

Additionally, validateCustomServerConfig (lines 167–199) passes the URL directly to validateAgainstCustomSchema without checking the URL scheme.

// internal/config/validation.go:316-333 (current)
func validateCustomSchemas(customSchemas map[string]interface{}) error {
    // ...
    for typeName := range customSchemas {
        // Only checks reserved type names — no URL scheme check
        if typeName == "stdio" || typeName == "http" {
            return rules.UnsupportedType(...)
        }
    }
    return nil
}

As a result, a configuration like:

{
  "customSchemas": {
    "mytype": "(insecure.example.com/redacted)
  }
}

is accepted without error, violating the MUST requirement.

Evidence from Tests:

The compliance tests T-CFG-010 and T-CFG-012 in internal/config/custom_types_test.go (lines 18, 21, 111) use httptest.NewServer (HTTP, not HTTPS) as the mock schema server and these tests pass — confirming HTTP URLs are accepted:

// internal/config/custom_types_test.go:18-19 (T-CFG-010)
// Create a mock HTTP server that returns a valid JSON schema for the custom type
mockSchemaServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

Gap:

The implementation silently accepts (redacted) and potentially (redacted) URLs for custom schemas, which is a security risk (man-in-the-middle attacks on schema fetching) and a MUST violation per Section 4.1.4.

Severity: Critical (MUST violation)

File References:

  • internal/config/validation.go:316-333validateCustomSchemas missing URL scheme check
  • internal/config/validation.go:167-199validateCustomServerConfig passes URL without HTTPS validation
  • internal/config/custom_types_test.go:18 — T-CFG-010 uses HTTP mock server (should expect rejection or use HTTPS)
  • internal/config/validate_against_custom_schema_test.go:63 — Test uses HTTP mock server

Suggested Remediation Tasks

Task 1: Enforce HTTPS-Only Custom Schema URLs

Description: Add URL scheme validation in validateCustomSchemas to reject any non-empty custom schema URL that does not start with https://.

Files to modify:

  • internal/config/validation.go — add HTTPS check in validateCustomSchemas

Suggested fix:

func validateCustomSchemas(customSchemas map[string]interface{}) error {
    if customSchemas == nil {
        return nil
    }
    for typeName, schemaValue := range customSchemas {
        if typeName == "stdio" || typeName == "http" {
            return rules.UnsupportedType(...)
        }
        // NEW: Enforce HTTPS-only for non-empty URLs
        if schemaURL, ok := schemaValue.(string); ok && schemaURL != "" {
            if !strings.HasPrefix(schemaURL, "https://") {
                return &rules.ValidationError{
                    Field:      "customSchemas." + typeName,
                    Message:    fmt.Sprintf("custom schema URL must use HTTPS, got '%s'", schemaURL),
                    JSONPath:   "customSchemas." + typeName,
                    Suggestion: "Use an HTTPS URL for the custom schema (e.g., '(example.com/redacted),
                }
            }
        }
    }
    return nil
}

Specification Reference: https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/mcp-gateway.md#414-custom-server-types
Estimated Effort: Small (1–2 hours including test updates)

Task 2: Update Compliance Tests to Use HTTPS Mock Servers

Description: Update T-CFG-010, T-CFG-012, T-CFG-014, and related tests to use httptest.NewTLSServer instead of httptest.NewServer, or add a separate test case that verifies HTTP URLs are rejected.

Files to modify:

  • internal/config/custom_types_test.go
  • internal/config/validate_against_custom_schema_test.go

Estimated Effort: Small (1–2 hours)


Compliance Status (Full Review)

Section Aspect Status
✅ Section 3.2.1 Containerization Requirement Compliant
✅ Section 4.1 Configuration Format Compliant
✅ Section 4.2 Variable Expression Rendering (fail-fast) Compliant
✅ Section 4.3 Configuration Validation (unknown fields, schema) Compliant
❌ Section 4.1.4 Custom Schema URLs MUST be HTTPS only Non-compliant
✅ Section 5.1.1 Endpoint Structure (/mcp/{server}, /health, /close) Compliant
✅ Section 5.1.3 Close Endpoint (idempotent, 410 on second call) Compliant
✅ Section 7 Authentication (401 on missing/invalid, /health exempt) Compliant
✅ Section 8.1.1 Health Response (status, specVersion, gatewayVersion) Compliant
✅ Section 4.1.3.1 Payload Directory Path Validation (absolute paths) Compliant
✅ T-CFG-010–014 Custom type compliance tests Present (HTTP mock servers)
✅ T-CFG-015–019 Mount compliance tests Present

References

Generated by Daily Compliance Checker

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions