[Low] ate-api-server accepts client certificates chained to system roots when --pod-identity-ca-certs is unset
Maintainers usually reply within 1 day
@abhisheksharma2411 is already working on this.
Since Oct 20, 2026.
- #3023 by @abhisheksharma2411 — open
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 75/100
Research direction
Start in cmd/ateapi/main.go at buildServerTLSConfig (lines 631–643) and check how the empty caCertsPath branch configures client certificates. Read the Go TLS client authentication behavior described in the issue, then run the relevant ate-api-server tests. Done when the empty-path configuration does not authenticate client certificates through system roots and the tests cover that behavior.
Written by the indexing model from the issue text.
Description
Summary
When --pod-identity-ca-certs is omitted (empty caCertsPath), cmd/ateapi/main.go:buildServerTLSConfig returns a tls.Config with ClientAuth: tls.VerifyClientCertIfGiven and ClientCAs: nil. Under Go's crypto/tls implementation, a nil ClientCAs causes client certificate verification to fall back to the host system root CAs, allowing any client certificate trusted by a system root containing a SPIFFE URI SAN to authenticate as an mTLS principal.
Details
In cmd/ateapi/main.go:631-643:
func buildServerTLSConfig(ctx context.Context, credBundlePath, caCertsPath string) (*tls.Config, error) {
serverCert := credbundle.Loader(credBundlePath)
const clientAuth = tls.VerifyClientCertIfGiven
if caCertsPath == "" {
return &tls.Config{
GetCertificate: serverCert,
ClientAuth: clientAuth,
}, nil
}
When caCertsPath == "", ClientCAs is left nil. In Go's crypto/tls/handshake_server.go:
opts := x509.VerifyOptions{
Roots: c.config.ClientCAs,
CurrentTime: c.config.time(),
Intermediates: x509.NewCertPool(),
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}
When opts.Roots is nil, x509.Certificate.Verify defaults to the host's system root CAs. If a client certificate verified by any system CA includes a URI SAN, apiauthn.UnaryServerInterceptor extracts the URI SAN via mtlsPeerIdentity and treats the caller as an authenticated mTLS principal without inspecting or requiring bearer token authentication.
Impact
Low: in standard deployments (manifests/ate-install/ate-api-server.yaml:180), --pod-identity-ca-certs is always provided. The fallback occurs only when --pod-identity-ca-certs is omitted. In standard deployments (manifests/ate-install/ate-api-server.yaml:180), --pod-identity-ca-certs is always provided, pointing to /run/podidentity.podcert.ate.dev/trust-bundle.pem. The fallback occurs only in non-standard or standalone deployments where --pod-identity-ca-certs is deliberately omitted. Furthermore, obtaining a publicly-trusted certificate containing a URI SAN (e.g., spiffe://...) with the clientAuth EKU is non-trivial under standard Web PKI CA baseline requirements. NetworkPolicies on ate-api-server also restrict ingress on port 443 to control plane pods or namespaces labeled ate.dev/api-access=true.
Suggested fix
When caCertsPath == "", explicitly disable client certificate verification by setting ClientAuth: tls.NoClientCert in the returned tls.Config:
if caCertsPath == "" {
return &tls.Config{
GetCertificate: serverCert,
ClientAuth: tls.NoClientCert,
}, nil
}
Related
No existing duplicate issues or PRs found.
- Dominant language
- Go
- Stars
- 5.7k
- Forks
- 612
- Avg merge
- 2d 13h
- Merged PRs (30d)
- 562
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from agent-substrate/substrate
-
area/security kind/bug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
agent-substrate/substrate#2935 ·
Maintainers usually reply within 1 day
-
[Low] CleanupSandboxState joins an unchecked id into paths it RemoveAll()sPossibly taken @ericcurtin claimed this today. Openarea/security kind/bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
agent-substrate/substrate#2932 ·
Maintainers usually reply within 1 day
-
[Low] guestVolumeSource can map host paths containing ".." outside the microVM guest sharePossibly taken @jiayimeow claimed this 3 days ago. Openarea/security kind/bug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
agent-substrate/substrate#2920 · 1 assignee ·
Maintainers usually reply within 1 day
-
[Low] setupImageVolumes builds host mount paths from vol.Name without a containment checkPossibly taken @abhisheksharma2411 claimed this 2 days ago. Openarea/security kind/bug
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
agent-substrate/substrate#2919 ·
Maintainers usually reply within 1 day
-
Cloud SQL backend: document (and optionally provision) Private Service Connect for ATE_API_POSTGRES_CLOUDSQL_IP_TYPE=pscPossibly taken A pull request linked to this issue is open or already merged. Openarea/dev-infra kind/docs kind/feature
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
agent-substrate/substrate#2875 ·
Maintainers usually reply within 1 day
All issues in agent-substrate/substrate
Similar issues
-
Aspect/API Severity/Major Type/Bug
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
wso2/api-platform#3899 ·
Maintainers usually reply within 1 day
-
bug needs-acceptance wg/agentic-context
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
vllm-project/semantic-router#5418 ·
Maintainers usually reply within 1 day
-
feature suggestion
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
openvibely/openvibely#1526 ·
Maintainers usually reply within 1 day
-
docs good first issue
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
Usenova-Labs/usenova-backend#36 ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day