Skip to content

[compliance] Compliance Gap: Volume Mount Mode Not Required by Validation #1224

Description

@github-actions

MCP Gateway Compliance Review - 2026-02-21

Summary

Found 1 compliance issue (MUST violation) during daily review of commit e3e8080.

Recent Changes Reviewed

  • Only commit e3e8080 affected workflow/CI files; no changes to internal/, main.go, or core gateway logic in the last 10 commits
  • Full compliance audit of current codebase performed against MCP Gateway Specification v1.8.0

Critical Issues (MUST violations)

1. Volume Mount Mode Is Accepted As Optional But Spec Requires It

Specification Section: 4.1.5 Volume Mounts for Stdio Servers
Deep Link: https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/mcp-gateway.md#415-volume-mounts-for-stdio-servers

Requirement:

"Volume mounts MUST use the format: "host:container:mode""

"Each mount string MUST conform to the 'host:container:mode' format"

"The mode MUST be either 'ro' (read-only) or 'rw' (read-write)"

Current State:

In internal/config/rules/rules.go:123-131, the function is documented and validated as accepting either the 2-part "source:dest" format or the 3-part "source:dest:mode" format:

// MountFormat validates a mount specification in the format "source:dest" or "source:dest:mode"
// ...
// - Mode (if provided) MUST be either "ro" (read-only) or "rw" (read-write)
func MountFormat(mount, jsonPath string, index int) *ValidationError {
    parts := strings.Split(mount, ":")
    if len(parts) < 2 || len(parts) > 3 {  // accepts 2 OR 3 parts
        ...
    }
    ...
    // Validate mode if provided  (mode treated as optional)
    if mode != "" && mode != "ro" && mode != "rw" {

This behavior is tested and confirmed in multiple test files:

  • internal/config/rules/rules_test.go:178: "valid mount without mode" passes validation
  • internal/config/validation_test.go:313: "valid mount without mode" passes validation
  • internal/config/validation_string_patterns_test.go:139: same
  • internal/config/validation_schema_test.go:395: same

Gap:

The specification in Section 4.1.5 unambiguously requires the 3-part "host:container:mode" format with mode being mandatory. The compliance test T-CFG-015 ("Valid volume mount format (host:container:mode)") is defined in Section 10.1.1 and describes the required format with an explicit mode component.

The implementation diverges from this by treating mode as optional, accepting "/host:/container" where the spec requires "/host:/container:ro" or "/host:/container:rw".

Security Impact:

This gap has security implications: without a required mode, a user may omit mode and rely on an undocumented default. Docker defaults to rw for mounts without a mode, meaning read-write access may be granted when read-only was intended. The spec explicitly recommends: "Read-only mounts ('ro') SHOULD be preferred when the server only needs to read data." Forcing explicit mode declaration aligns with the principle of least privilege.

Severity: Critical (MUST violation)

File References:

  • internal/config/rules/rules.go:123-128 — comment and function signature treating mode as optional
  • internal/config/rules/rules.go:131 — condition len(parts) < 2 || len(parts) > 3 accepts 2-part format
  • internal/config/rules/rules.go:178-180 — mode-only validation is skipped if empty
  • internal/config/rules/rules_test.go:178-186 — "valid mount without mode" test case
  • internal/config/validation_test.go:313-320 — "valid mount without mode" test case

Suggested Fix:

  1. Update MountFormat in internal/config/rules/rules.go to require exactly 3 parts:
// MountFormat validates a mount specification in the format "source:dest:mode"
// Per MCP Gateway specification v1.7.0 section 4.1.5:
// - Host path MUST be an absolute path
// - Container path MUST be an absolute path
// - Mode MUST be either "ro" (read-only) or "rw" (read-write)
func MountFormat(mount, jsonPath string, index int) *ValidationError {
    parts := strings.Split(mount, ":")
    if len(parts) != 3 {  // require exactly 3 parts
        return &ValidationError{
            Field:      "mounts",
            Message:    fmt.Sprintf("invalid mount format '%s' (expected 'source:dest:mode')", mount),
            JSONPath:   fmt.Sprintf("%s.mounts[%d]", jsonPath, index),
            Suggestion: "Use format 'source:dest:mode' where mode is 'ro' (read-only) or 'rw' (read-write), e.g. '/host/path:/container/path:ro'",
        }
    }
    ...
  1. Update the related test cases to remove "valid mount without mode" cases and instead add tests that verify 2-part mounts are rejected.

  2. Update the error message suggestion in rules.go:136 to only show the 3-part format.


Compliance Status

Section Status
✅ Configuration Format (Section 4.1) Compliant
✅ Variable Expression Rendering (Section 4.2) Compliant
command field rejected (Section 3.2.1) Compliant
✅ Containerization requirement (Section 3.2.1) Compliant
✅ Payload directory validation (Section 4.1.3.1) Compliant
❌ Volume mount mode required (Section 4.1.5) Non-compliant (MUST violation)
✅ HTTP server mounts rejected (Section 4.1.5) Compliant
✅ Health endpoint specVersion/gatewayVersion (Section 8.1.1) Compliant ("1.8.0")
/close endpoint idempotency — HTTP 410 (Section 5.1.3) Compliant
/close endpoint requires auth (Section 5.1.3 / Appendix D.4) Compliant
/health endpoint auth-exempt (Section 7.4) Compliant
✅ Stdout config output — type, url, headers (Section 5.4) Compliant
✅ HTTP connection failure not silently ignored (Section 5.2.2) Compliant
✅ Server isolation (Section 6) Compliant
✅ Authentication (Section 7) Compliant

Remediation Task

Task 1: Require Explicit Mount Mode in Volume Mount Validation

Description: Update MountFormat validation to require exactly 3 components (host:container:mode) instead of accepting the 2-part form. Remove "valid mount without mode" test cases and add cases confirming 2-part mounts are rejected.

Files:

  • internal/config/rules/rules.go — change length check and make mode required
  • internal/config/rules/rules_test.go — update test cases
  • internal/config/validation_test.go — update test cases
  • internal/config/validation_string_patterns_test.go — update test cases
  • internal/config/validation_schema_test.go — update test cases

Specification Reference: https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/mcp-gateway.md#415-volume-mounts-for-stdio-servers

Compliance Tests Addressed: T-CFG-015, T-CFG-016, T-CFG-017

Estimated Effort: Small (1-2 hours)


References

Generated by Daily Compliance Checker

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions