User-controlled cert_dir enables arbitrary file read in mTLS onboarding #682
Labels
No labels
1week
2weeks
Failed compliance check
IP cameras
NATS
Possible security concern
Review effort 1/5
Review effort 2/5
Review effort 3/5
Review effort 4/5
Review effort 5/5
UI
aardvark
accessibility
amd64
api
arm64
auth
back-end
bgp
blog
bug
build
checkers
ci-cd
cleanup
cnpg
codex
core
dependencies
device-management
documentation
duplicate
dusk
ebpf
enhancement
eta 1d
eta 1hr
eta 3d
eta 3hr
feature
fieldsurvey
github_actions
go
good first issue
help wanted
invalid
javascript
k8s
log-collector
mapper
mtr
needs-triage
netflow
network-sweep
observability
oracle
otel
plug-in
proton
python
question
reddit
redhat
research
rperf
rperf-checker
rust
sdk
security
serviceradar-agent
serviceradar-agent-gateway
serviceradar-web
serviceradar-web-ng
siem
snmp
sysmon
topology
ubiquiti
wasm
wontfix
zen-engine
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
carverauto/serviceradar#682
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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
buildMTLSBundlefunction inpkg/core/edge_onboarding.gogenerates mTLS certificates for edge devices during the onboarding process. It reads CA certificate and key files from disk to sign new client certificates.cert_dir, butcert_diritself is user-controlled via themetadata_jsonfield and is never validated to be within an allowed directory.cert_dirto any directory on the system (e.g.,/etc) andca_cert_pathto 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.cert_dirmetadata field during package creation, potentially accessing sensitive system files, SSL private keys, application secrets, or other confidential data.Code with bug
Evidence
Example
Attack scenario:
The validation logic executes:
certDir = "/etc"(from user input)absCertDir = "/etc"(afterfilepath.Abs)absCaPath = "/etc/shadow"(from user input, afterfilepath.Abs)"/etc/"(i.e.,absCertDir + filepath.Separator)"/etc/shadow"start with"/etc/"? YES ✓Validation passes, and
os.ReadFile("/etc/shadow")is called.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:
metadata["cert_dir"] = "/etc",metadata["ca_cert_path"] = "/etc/shadow"certDir = "/etc"caPath = "/etc/shadow"absCertDir = "/etc"absCaPath = "/etc/shadow"strings.HasPrefix("/etc/shadow", "/etc/")→ trueos.ReadFile("/etc/shadow")executes successfullyFailing test
Test script
Test output
Full context
The
buildMTLSBundlefunction is called during the edge onboarding package creation flow:API Entry Point: An authenticated user sends a POST request to create an edge onboarding package via
/v1/edge/onboarding/packages(handled byhandleEdgePackageCreateinpkg/core/api/edge_onboarding.go)Authentication: The request requires authentication (the code retrieves user information via
auth.GetUserFromContext), so this is not exploitable by unauthenticated attackers.Package Creation: The request is forwarded to
edgeOnboardingService.CreatePackage(pkg/core/edge_onboarding.go:767)Security Mode Check: If the package uses
security_mode: "mtls"(line 907), the flow callscreateMTLSPackage(line 908)Bundle Generation:
createMTLSPackagecallsbuildMTLSBundle(line 2061) with the user-provided metadata mapVulnerable Code:
buildMTLSBundle(line 2118) readscert_dir,ca_cert_path, andca_key_pathfrom the metadata without validating thatcert_diris within an allowed directoryFile Access: The function calls
os.ReadFile(absCaPath)(line 2148) andos.ReadFile(absCaKeyPath)(line 2157), potentially reading arbitrary system filesThe metadata is provided by the user in the
metadata_jsonfield of the package creation request:Why has this bug gone undetected?
This vulnerability has likely gone undetected for several reasons:
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.
Parsing Failure: After reading the file, the code attempts to parse it as an X.509 certificate (
parseCACertificateat 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.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.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.
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.
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.
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_diritself is within an allowed directory. Add a configuration option for allowed certificate directories and check against it:Alternatively, consider removing the ability for users to specify custom
cert_dirvalues entirely, restricting all mTLS operations to usedefaultCertDiror a configuration-specified directory.