User-controlled cert_dir enables arbitrary file read in mTLS onboarding #682

Closed
opened 2026-03-28 04:27:23 +00:00 by mfreeman451 · 0 comments
Owner

Imported from GitHub.

Original GitHub issue: #2144
Original author: @mfreeman451
Original URL: https://github.com/carverauto/serviceradar/issues/2144
Original created: 2025-12-16T05:16:06Z


Summary

  • Context: The buildMTLSBundle function in pkg/core/edge_onboarding.go generates mTLS certificates for edge devices during the onboarding process. It reads CA certificate and key files from disk to sign new client certificates.
  • Bug: The function validates that CA cert/key paths are within cert_dir, but cert_dir itself is user-controlled via the metadata_json field and is never validated to be within an allowed directory.
  • Actual vs. expected: An authenticated user can set cert_dir to any directory on the system (e.g., /etc) and ca_cert_path to any file within it (e.g., /etc/shadow). The validation passes because the file is "within" the user-specified directory. The expected behavior is that only files within a safe, predetermined directory (like /etc/serviceradar/certs) can be accessed.
  • Impact: An authenticated user can read arbitrary files from the filesystem by controlling the cert_dir metadata field during package creation, potentially accessing sensitive system files, SSL private keys, application secrets, or other confidential data.

Code with bug

func (s *edgeOnboardingService) buildMTLSBundle(componentType models.EdgeOnboardingComponentType, componentID string, metadata map[string]string, now time.Time) (*mtls.Bundle, error) {
	certDir := strings.TrimSpace(metadata["cert_dir"])  // <-- BUG 🔴 User-controlled, no validation
	if certDir == "" {
		certDir = defaultCertDir
	}

	caPath := firstNonEmpty(strings.TrimSpace(metadata["ca_cert_path"]), filepath.Join(certDir, "root.pem"))
	caKeyPath := firstNonEmpty(strings.TrimSpace(metadata["ca_key_path"]), filepath.Join(certDir, "root-key.pem"))

	// Validate paths to prevent path traversal attacks
	absCertDir, err := filepath.Abs(certDir)
	if err != nil {
		return nil, fmt.Errorf("invalid cert_dir path: %w", err)
	}
	absCaPath, err := filepath.Abs(caPath)
	if err != nil {
		return nil, fmt.Errorf("invalid ca_cert_path: %w", err)
	}
	absCaKeyPath, err := filepath.Abs(caKeyPath)
	if err != nil {
		return nil, fmt.Errorf("invalid ca_key_path: %w", err)
	}
	// Ensure CA cert and key paths are within the allowed certDir
	if !strings.HasPrefix(absCaPath, absCertDir+string(filepath.Separator)) {  // <-- BUG 🔴 Only validates relative to user-controlled certDir
		return nil, fmt.Errorf("ca_cert_path %q outside %q: %w", caPath, certDir, ErrPathOutsideAllowedDir)
	}
	if !strings.HasPrefix(absCaKeyPath, absCertDir+string(filepath.Separator)) {
		return nil, fmt.Errorf("ca_key_path %q outside %q: %w", caKeyPath, certDir, ErrPathOutsideAllowedDir)
	}

	caPEM, err := os.ReadFile(absCaPath)  // <-- Reads arbitrary file
	if err != nil {
		return nil, fmt.Errorf("read ca cert from %s: %w", absCaPath, err)
	}
	// ... continues to parse and use the file

Evidence

Example

Attack scenario:

  1. Authenticated user creates an edge onboarding package with the following metadata:
{
  "cert_dir": "/etc",
  "ca_cert_path": "/etc/shadow",
  "ca_key_path": "/etc/shadow",
  "security_mode": "mtls"
}
  1. The validation logic executes:

    • certDir = "/etc" (from user input)
    • absCertDir = "/etc" (after filepath.Abs)
    • absCaPath = "/etc/shadow" (from user input, after filepath.Abs)
    • Required prefix: "/etc/" (i.e., absCertDir + filepath.Separator)
    • Check: Does "/etc/shadow" start with "/etc/"? YES
  2. Validation passes, and os.ReadFile("/etc/shadow") is called.

  3. The file contents are returned to the attacker (though they may fail at the certificate parsing stage, the file has been read and potentially leaked through error messages or side channels).

Step-by-step variable values:

  • Input: metadata["cert_dir"] = "/etc", metadata["ca_cert_path"] = "/etc/shadow"
  • After line 2119: certDir = "/etc"
  • After line 2124: caPath = "/etc/shadow"
  • After line 2128: absCertDir = "/etc"
  • After line 2132: absCaPath = "/etc/shadow"
  • Line 2141: Check strings.HasPrefix("/etc/shadow", "/etc/")true
  • Line 2148: os.ReadFile("/etc/shadow") executes successfully

Failing test

Test script

package main

import (
	"fmt"
	"path/filepath"
	"strings"
)

// This test demonstrates the path traversal vulnerability in buildMTLSBundle
func main() {
	fmt.Println("=== Path Traversal Vulnerability Test ===\n")

	// Attack scenario 1: Read sensitive system file
	attackCertDir := "/etc"
	attackCaPath := "/etc/shadow"

	absCertDir, _ := filepath.Abs(attackCertDir)
	absCaPath, _ := filepath.Abs(attackCaPath)

	requiredPrefix := absCertDir + string(filepath.Separator)
	validationPasses := strings.HasPrefix(absCaPath, requiredPrefix)

	fmt.Printf("Attack 1: Reading /etc/shadow\n")
	fmt.Printf("  cert_dir: %s\n", attackCertDir)
	fmt.Printf("  ca_cert_path: %s\n", attackCaPath)
	fmt.Printf("  Required prefix: %s\n", requiredPrefix)
	fmt.Printf("  Validation passes: %v\n", validationPasses)

	if validationPasses {
		fmt.Println("  ✗ VULNERABILITY: Attacker can read /etc/shadow\n")
	}

	// Attack scenario 2: Read SSL private keys
	attack2CertDir := "/etc/ssl/private"
	attack2CaPath := "/etc/ssl/private/server.key"

	absAttack2CertDir, _ := filepath.Abs(attack2CertDir)
	absAttack2CaPath, _ := filepath.Abs(attack2CaPath)

	requiredPrefix2 := absAttack2CertDir + string(filepath.Separator)
	validation2Passes := strings.HasPrefix(absAttack2CaPath, requiredPrefix2)

	fmt.Printf("Attack 2: Reading SSL private key\n")
	fmt.Printf("  cert_dir: %s\n", attack2CertDir)
	fmt.Printf("  ca_cert_path: %s\n", attack2CaPath)
	fmt.Printf("  Required prefix: %s\n", requiredPrefix2)
	fmt.Printf("  Validation passes: %v\n", validation2Passes)

	if validation2Passes {
		fmt.Println("  ✗ VULNERABILITY: Attacker can read SSL private keys\n")
	}

	// Show what a correct check would look like
	fmt.Println("=== Correct Validation ===")
	allowedDir := "/etc/serviceradar/certs"
	absAllowedDir, _ := filepath.Abs(allowedDir)

	// For attack 1
	relPath1, err1 := filepath.Rel(absAllowedDir, absCaPath)
	correctCheck1 := err1 == nil && !strings.HasPrefix(relPath1, "..")

	fmt.Printf("Attack 1 against allowed dir (%s):\n", allowedDir)
	fmt.Printf("  Relative path: %s (err: %v)\n", relPath1, err1)
	fmt.Printf("  Correct check passes: %v\n", correctCheck1)
	if !correctCheck1 {
		fmt.Println("  ✓ Attack correctly blocked\n")
	}
}

Test output

=== Path Traversal Vulnerability Test ===

Attack 1: Reading /etc/shadow
  cert_dir: /etc
  ca_cert_path: /etc/shadow
  Required prefix: /etc/
  Validation passes: true
  ✗ VULNERABILITY: Attacker can read /etc/shadow

Attack 2: Reading SSL private key
  cert_dir: /etc/ssl/private
  ca_cert_path: /etc/ssl/private/server.key
  Required prefix: /etc/ssl/private/
  Validation passes: true
  ✗ VULNERABILITY: Attacker can read SSL private keys

=== Correct Validation ===
Attack 1 against allowed dir (/etc/serviceradar/certs):
  Relative path: ../../../shadow (err: <nil>)
  Correct check passes: false
  ✓ Attack correctly blocked

Full context

The buildMTLSBundle function is called during the edge onboarding package creation flow:

  1. API Entry Point: An authenticated user sends a POST request to create an edge onboarding package via /v1/edge/onboarding/packages (handled by handleEdgePackageCreate in pkg/core/api/edge_onboarding.go)

  2. Authentication: The request requires authentication (the code retrieves user information via auth.GetUserFromContext), so this is not exploitable by unauthenticated attackers.

  3. Package Creation: The request is forwarded to edgeOnboardingService.CreatePackage (pkg/core/edge_onboarding.go:767)

  4. Security Mode Check: If the package uses security_mode: "mtls" (line 907), the flow calls createMTLSPackage (line 908)

  5. Bundle Generation: createMTLSPackage calls buildMTLSBundle (line 2061) with the user-provided metadata map

  6. Vulnerable Code: buildMTLSBundle (line 2118) reads cert_dir, ca_cert_path, and ca_key_path from the metadata without validating that cert_dir is within an allowed directory

  7. File Access: The function calls os.ReadFile(absCaPath) (line 2148) and os.ReadFile(absCaKeyPath) (line 2157), potentially reading arbitrary system files

The metadata is provided by the user in the metadata_json field of the package creation request:

POST /v1/edge/onboarding/packages
{
  "label": "malicious-package",
  "component_type": "checker",
  "checker_kind": "sysmon",
  "metadata_json": "{\"cert_dir\":\"/etc\",\"ca_cert_path\":\"/etc/shadow\",\"ca_key_path\":\"/etc/passwd\",\"security_mode\":\"mtls\"}"
}

Why has this bug gone undetected?

This vulnerability has likely gone undetected for several reasons:

  1. Authentication Required: The attack requires an authenticated user, limiting the potential attackers to those with valid credentials. This reduces the likelihood of discovery through external security scanning.

  2. Parsing Failure: After reading the file, the code attempts to parse it as an X.509 certificate (parseCACertificate at line 2152). Most arbitrary files will fail this parsing step, causing the attack to fail with a generic "parse ca certificate" error rather than exposing file contents directly.

  3. Limited Use Case: The mTLS security mode is only used for specific component types (particularly checkers like sysmon), so not all edge onboarding flows exercise this code path.

  4. Partial Validation: The presence of some path validation (checking that cert/key paths are within cert_dir) gives a false sense of security, potentially causing reviewers to assume the validation is complete.

  5. Complex Flow: The vulnerability requires understanding the interaction between user input (metadata_json), the CreatePackage API, and the buildMTLSBundle function—a multi-step code path that may not be obvious during code review.

  6. Side Channel Exploitation Required: The file contents aren't directly returned to the user in the response. An attacker would need to use side channels (timing, error messages, or subsequent certificate operations) to extract data, making the exploit less straightforward.

  7. Recent Feature: The path traversal validation was added in commit 2c24dcb5 ("initial"), suggesting this is a relatively new feature that may not have received extensive security review.

Recommended fix

Validate that cert_dir itself is within an allowed directory. Add a configuration option for allowed certificate directories and check against it:

func (s *edgeOnboardingService) buildMTLSBundle(componentType models.EdgeOnboardingComponentType, componentID string, metadata map[string]string, now time.Time) (*mtls.Bundle, error) {
	certDir := strings.TrimSpace(metadata["cert_dir"])
	if certDir == "" {
		certDir = defaultCertDir
	}

	// FIX 🟢: Validate cert_dir is within allowed base directory
	allowedBaseDir := defaultCertDir
	if s.cfg.MTLSCertBaseDir != "" {
		allowedBaseDir = s.cfg.MTLSCertBaseDir
	}

	absAllowedDir, err := filepath.Abs(allowedBaseDir)
	if err != nil {
		return nil, fmt.Errorf("invalid mtls cert base dir: %w", err)
	}

	absCertDir, err := filepath.Abs(certDir)
	if err != nil {
		return nil, fmt.Errorf("invalid cert_dir path: %w", err)
	}

	// FIX 🟢: Ensure cert_dir is within the allowed base directory
	relPath, err := filepath.Rel(absAllowedDir, absCertDir)
	if err != nil || strings.HasPrefix(relPath, "..") {
		return nil, fmt.Errorf("cert_dir %q outside allowed directory %q: %w", certDir, allowedBaseDir, ErrPathOutsideAllowedDir)
	}

	caPath := firstNonEmpty(strings.TrimSpace(metadata["ca_cert_path"]), filepath.Join(certDir, "root.pem"))
	caKeyPath := firstNonEmpty(strings.TrimSpace(metadata["ca_key_path"]), filepath.Join(certDir, "root-key.pem"))

	// ... rest of existing validation continues

Alternatively, consider removing the ability for users to specify custom cert_dir values entirely, restricting all mTLS operations to use defaultCertDir or a configuration-specified directory.

Imported from GitHub. Original GitHub issue: #2144 Original author: @mfreeman451 Original URL: https://github.com/carverauto/serviceradar/issues/2144 Original created: 2025-12-16T05:16:06Z --- # Summary - **Context**: The `buildMTLSBundle` function in `pkg/core/edge_onboarding.go` generates mTLS certificates for edge devices during the onboarding process. It reads CA certificate and key files from disk to sign new client certificates. - **Bug**: The function validates that CA cert/key paths are within `cert_dir`, but `cert_dir` itself is user-controlled via the `metadata_json` field and is never validated to be within an allowed directory. - **Actual vs. expected**: An authenticated user can set `cert_dir` to any directory on the system (e.g., `/etc`) and `ca_cert_path` to any file within it (e.g., `/etc/shadow`). The validation passes because the file is "within" the user-specified directory. The expected behavior is that only files within a safe, predetermined directory (like `/etc/serviceradar/certs`) can be accessed. - **Impact**: An authenticated user can read arbitrary files from the filesystem by controlling the `cert_dir` metadata field during package creation, potentially accessing sensitive system files, SSL private keys, application secrets, or other confidential data. # Code with bug ```go func (s *edgeOnboardingService) buildMTLSBundle(componentType models.EdgeOnboardingComponentType, componentID string, metadata map[string]string, now time.Time) (*mtls.Bundle, error) { certDir := strings.TrimSpace(metadata["cert_dir"]) // <-- BUG 🔴 User-controlled, no validation if certDir == "" { certDir = defaultCertDir } caPath := firstNonEmpty(strings.TrimSpace(metadata["ca_cert_path"]), filepath.Join(certDir, "root.pem")) caKeyPath := firstNonEmpty(strings.TrimSpace(metadata["ca_key_path"]), filepath.Join(certDir, "root-key.pem")) // Validate paths to prevent path traversal attacks absCertDir, err := filepath.Abs(certDir) if err != nil { return nil, fmt.Errorf("invalid cert_dir path: %w", err) } absCaPath, err := filepath.Abs(caPath) if err != nil { return nil, fmt.Errorf("invalid ca_cert_path: %w", err) } absCaKeyPath, err := filepath.Abs(caKeyPath) if err != nil { return nil, fmt.Errorf("invalid ca_key_path: %w", err) } // Ensure CA cert and key paths are within the allowed certDir if !strings.HasPrefix(absCaPath, absCertDir+string(filepath.Separator)) { // <-- BUG 🔴 Only validates relative to user-controlled certDir return nil, fmt.Errorf("ca_cert_path %q outside %q: %w", caPath, certDir, ErrPathOutsideAllowedDir) } if !strings.HasPrefix(absCaKeyPath, absCertDir+string(filepath.Separator)) { return nil, fmt.Errorf("ca_key_path %q outside %q: %w", caKeyPath, certDir, ErrPathOutsideAllowedDir) } caPEM, err := os.ReadFile(absCaPath) // <-- Reads arbitrary file if err != nil { return nil, fmt.Errorf("read ca cert from %s: %w", absCaPath, err) } // ... continues to parse and use the file ``` # Evidence ## Example **Attack scenario:** 1. Authenticated user creates an edge onboarding package with the following metadata: ```json { "cert_dir": "/etc", "ca_cert_path": "/etc/shadow", "ca_key_path": "/etc/shadow", "security_mode": "mtls" } ``` 2. The validation logic executes: - `certDir = "/etc"` (from user input) - `absCertDir = "/etc"` (after `filepath.Abs`) - `absCaPath = "/etc/shadow"` (from user input, after `filepath.Abs`) - Required prefix: `"/etc/"` (i.e., `absCertDir + filepath.Separator`) - Check: Does `"/etc/shadow"` start with `"/etc/"`? **YES** ✓ 3. Validation passes, and `os.ReadFile("/etc/shadow")` is called. 4. The file contents are returned to the attacker (though they may fail at the certificate parsing stage, the file has been read and potentially leaked through error messages or side channels). **Step-by-step variable values:** - Input: `metadata["cert_dir"] = "/etc"`, `metadata["ca_cert_path"] = "/etc/shadow"` - After line 2119: `certDir = "/etc"` - After line 2124: `caPath = "/etc/shadow"` - After line 2128: `absCertDir = "/etc"` - After line 2132: `absCaPath = "/etc/shadow"` - Line 2141: Check `strings.HasPrefix("/etc/shadow", "/etc/")` → **true** - Line 2148: `os.ReadFile("/etc/shadow")` executes successfully ## Failing test ### Test script ```go package main import ( "fmt" "path/filepath" "strings" ) // This test demonstrates the path traversal vulnerability in buildMTLSBundle func main() { fmt.Println("=== Path Traversal Vulnerability Test ===\n") // Attack scenario 1: Read sensitive system file attackCertDir := "/etc" attackCaPath := "/etc/shadow" absCertDir, _ := filepath.Abs(attackCertDir) absCaPath, _ := filepath.Abs(attackCaPath) requiredPrefix := absCertDir + string(filepath.Separator) validationPasses := strings.HasPrefix(absCaPath, requiredPrefix) fmt.Printf("Attack 1: Reading /etc/shadow\n") fmt.Printf(" cert_dir: %s\n", attackCertDir) fmt.Printf(" ca_cert_path: %s\n", attackCaPath) fmt.Printf(" Required prefix: %s\n", requiredPrefix) fmt.Printf(" Validation passes: %v\n", validationPasses) if validationPasses { fmt.Println(" ✗ VULNERABILITY: Attacker can read /etc/shadow\n") } // Attack scenario 2: Read SSL private keys attack2CertDir := "/etc/ssl/private" attack2CaPath := "/etc/ssl/private/server.key" absAttack2CertDir, _ := filepath.Abs(attack2CertDir) absAttack2CaPath, _ := filepath.Abs(attack2CaPath) requiredPrefix2 := absAttack2CertDir + string(filepath.Separator) validation2Passes := strings.HasPrefix(absAttack2CaPath, requiredPrefix2) fmt.Printf("Attack 2: Reading SSL private key\n") fmt.Printf(" cert_dir: %s\n", attack2CertDir) fmt.Printf(" ca_cert_path: %s\n", attack2CaPath) fmt.Printf(" Required prefix: %s\n", requiredPrefix2) fmt.Printf(" Validation passes: %v\n", validation2Passes) if validation2Passes { fmt.Println(" ✗ VULNERABILITY: Attacker can read SSL private keys\n") } // Show what a correct check would look like fmt.Println("=== Correct Validation ===") allowedDir := "/etc/serviceradar/certs" absAllowedDir, _ := filepath.Abs(allowedDir) // For attack 1 relPath1, err1 := filepath.Rel(absAllowedDir, absCaPath) correctCheck1 := err1 == nil && !strings.HasPrefix(relPath1, "..") fmt.Printf("Attack 1 against allowed dir (%s):\n", allowedDir) fmt.Printf(" Relative path: %s (err: %v)\n", relPath1, err1) fmt.Printf(" Correct check passes: %v\n", correctCheck1) if !correctCheck1 { fmt.Println(" ✓ Attack correctly blocked\n") } } ``` ### Test output ``` === Path Traversal Vulnerability Test === Attack 1: Reading /etc/shadow cert_dir: /etc ca_cert_path: /etc/shadow Required prefix: /etc/ Validation passes: true ✗ VULNERABILITY: Attacker can read /etc/shadow Attack 2: Reading SSL private key cert_dir: /etc/ssl/private ca_cert_path: /etc/ssl/private/server.key Required prefix: /etc/ssl/private/ Validation passes: true ✗ VULNERABILITY: Attacker can read SSL private keys === Correct Validation === Attack 1 against allowed dir (/etc/serviceradar/certs): Relative path: ../../../shadow (err: <nil>) Correct check passes: false ✓ Attack correctly blocked ``` # Full context The `buildMTLSBundle` function is called during the edge onboarding package creation flow: 1. **API Entry Point**: An authenticated user sends a POST request to create an edge onboarding package via `/v1/edge/onboarding/packages` (handled by `handleEdgePackageCreate` in `pkg/core/api/edge_onboarding.go`) 2. **Authentication**: The request requires authentication (the code retrieves user information via `auth.GetUserFromContext`), so this is not exploitable by unauthenticated attackers. 3. **Package Creation**: The request is forwarded to `edgeOnboardingService.CreatePackage` (`pkg/core/edge_onboarding.go:767`) 4. **Security Mode Check**: If the package uses `security_mode: "mtls"` (line 907), the flow calls `createMTLSPackage` (line 908) 5. **Bundle Generation**: `createMTLSPackage` calls `buildMTLSBundle` (line 2061) with the user-provided metadata map 6. **Vulnerable Code**: `buildMTLSBundle` (line 2118) reads `cert_dir`, `ca_cert_path`, and `ca_key_path` from the metadata without validating that `cert_dir` is within an allowed directory 7. **File Access**: The function calls `os.ReadFile(absCaPath)` (line 2148) and `os.ReadFile(absCaKeyPath)` (line 2157), potentially reading arbitrary system files The metadata is provided by the user in the `metadata_json` field of the package creation request: ``` POST /v1/edge/onboarding/packages { "label": "malicious-package", "component_type": "checker", "checker_kind": "sysmon", "metadata_json": "{\"cert_dir\":\"/etc\",\"ca_cert_path\":\"/etc/shadow\",\"ca_key_path\":\"/etc/passwd\",\"security_mode\":\"mtls\"}" } ``` # Why has this bug gone undetected? This vulnerability has likely gone undetected for several reasons: 1. **Authentication Required**: The attack requires an authenticated user, limiting the potential attackers to those with valid credentials. This reduces the likelihood of discovery through external security scanning. 2. **Parsing Failure**: After reading the file, the code attempts to parse it as an X.509 certificate (`parseCACertificate` at line 2152). Most arbitrary files will fail this parsing step, causing the attack to fail with a generic "parse ca certificate" error rather than exposing file contents directly. 3. **Limited Use Case**: The mTLS security mode is only used for specific component types (particularly checkers like `sysmon`), so not all edge onboarding flows exercise this code path. 4. **Partial Validation**: The presence of *some* path validation (checking that cert/key paths are within cert_dir) gives a false sense of security, potentially causing reviewers to assume the validation is complete. 5. **Complex Flow**: The vulnerability requires understanding the interaction between user input (metadata_json), the CreatePackage API, and the buildMTLSBundle function—a multi-step code path that may not be obvious during code review. 6. **Side Channel Exploitation Required**: The file contents aren't directly returned to the user in the response. An attacker would need to use side channels (timing, error messages, or subsequent certificate operations) to extract data, making the exploit less straightforward. 7. **Recent Feature**: The path traversal validation was added in commit 2c24dcb5 ("initial"), suggesting this is a relatively new feature that may not have received extensive security review. # Recommended fix Validate that `cert_dir` itself is within an allowed directory. Add a configuration option for allowed certificate directories and check against it: ```go func (s *edgeOnboardingService) buildMTLSBundle(componentType models.EdgeOnboardingComponentType, componentID string, metadata map[string]string, now time.Time) (*mtls.Bundle, error) { certDir := strings.TrimSpace(metadata["cert_dir"]) if certDir == "" { certDir = defaultCertDir } // FIX 🟢: Validate cert_dir is within allowed base directory allowedBaseDir := defaultCertDir if s.cfg.MTLSCertBaseDir != "" { allowedBaseDir = s.cfg.MTLSCertBaseDir } absAllowedDir, err := filepath.Abs(allowedBaseDir) if err != nil { return nil, fmt.Errorf("invalid mtls cert base dir: %w", err) } absCertDir, err := filepath.Abs(certDir) if err != nil { return nil, fmt.Errorf("invalid cert_dir path: %w", err) } // FIX 🟢: Ensure cert_dir is within the allowed base directory relPath, err := filepath.Rel(absAllowedDir, absCertDir) if err != nil || strings.HasPrefix(relPath, "..") { return nil, fmt.Errorf("cert_dir %q outside allowed directory %q: %w", certDir, allowedBaseDir, ErrPathOutsideAllowedDir) } caPath := firstNonEmpty(strings.TrimSpace(metadata["ca_cert_path"]), filepath.Join(certDir, "root.pem")) caKeyPath := firstNonEmpty(strings.TrimSpace(metadata["ca_key_path"]), filepath.Join(certDir, "root-key.pem")) // ... rest of existing validation continues ``` Alternatively, consider removing the ability for users to specify custom `cert_dir` values entirely, restricting all mTLS operations to use `defaultCertDir` or a configuration-specified directory.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
carverauto/serviceradar#682
No description provided.