The Hidden Risk in Service Mesh mTLS: When Your Sidecar Becomes a Trojan Horse

Written by
Zsolt Varga
Published on
August 4, 2025

Introduction

Service meshes like Istio promise stronger zero-trust security by automating mutual TLS (mTLS) between workloads. By offloading certificate management to a sidecar proxy (typically Envoy), mTLS becomes transparent to application developers. But this convenience hides a critical flaw, rogue processes on the same node or inside the same pod can impersonate trusted workloads.

As we discussed in our blog post - Rethinking Workload Identity at the Kernel Level, sidecars and proxies simplify network security but introduce ambiguity around who is actually speaking on the wire. It's time to rethink how workload identity is established and enforced.

At Riptides, we believe that true zero trust starts not at the edge, but inside the kernel - where identity can be cryptographically anchored to the process itself. If a proxy can't distinguish between two processes behind the same socket, it's not enforcing zero trust - it's just forwarding packets.

How Istio Implements mTLS

In Istio (and similar meshes like Linkerd), secure communication between services is achieved through automatic mTLS, implemented via:

  • A dedicated sidecar injected into each pod to handle ingress and egress.
  • The Istio control plane component (istiod) issuing X.509 certificates to Envoy via SDS (Secret Discovery Service).
  • Certificates containing SPIFFE-based identities, e.g.,
    spiffe://cluster.local/ns/default/sa/myserviceaccount
  • iptables (or similar) rules routing all pod traffic through Envoy.
  • Envoy handling mTLS handshakes and peer identity verification.

Certificate Lifecycle

  • Istiod issues short-lived certificates (default TTL: 24h).
  • Certificates are rotated automatically via SDS pushes.
  • The workload itself never sees the private key - only Envoy handles it.

This architecture makes strong cryptographic identity "invisible" to the application, and that’s where the problem begins.

The Trust Assumption and Its Flaw

The system implicitly trusts any connection that: arrives over mTLS and presents a valid SPIFFE identity.

While this is technically sound at the network layer, it is not sufficient at the workload level.

Envoy authenticates other Envoys and not the actual application inside the pod. The application:

  • Does not participate in the TLS handshake.
  • Cannot sign requests or cryptographically assert its identity.
  • Relies entirely on Envoy to represent it.

Attack Scenario: Rogue Process Impersonation

Here’s how a process-level impersonation attack can happen, even in a pod with a single application container:

  1. Step 1: Initial Compromise
    An attacker exploits a vulnerability in the application or breaks out of a container into the pod namespace.
  2. Step 2: Reconnaissance
    They find Envoy listening on 127.0.0.1:15001 (outbound) and 127.0.0.1:15006 (inbound) - standard Istio ports.
  3. Step 3: Forged Requests
    Using curl, netcat, or a custom application, the attacker sends arbitrary HTTP requests to Envoy’s outbound listener.
  4. Step 4: mTLS Proxying
    Envoy forwards the request over mTLS using the pod’s legitimate certificate. The receiving Envoy verifies the SPIFFE ID and allows the request.
  5. Step 5: Impersonation Complete
    The target service sees a valid, authenticated SPIFFE identity - and has no way to tell it wasn’t the real application.

This is not a theoretical issue - it’s a byproduct of conflating network identity with process identity.

Technical Deep Dive

Let’s inspect the Envoy configuration that enables this behavior

Outbound cluster:

clusters:
- name: outbound|8080||target-service.default.svc.cluster.local
  transport_socket:
    name: envoy.transport_sockets.tls
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
      common_tls_context:
        tls_certificate_sds_secret_configs:
        - name: default

Inbound listener:

listeners:
- address:
    socket_address:
      address: 127.0.0.1
      port_value: 15006
  filter_chains:
  - filters:
    - name: envoy.filters.network.http_connection_manager

The critical detail: any process in the pod can access localhost:15001 or 15006. There is no enforcement at the socket or process boundary. Envoy assumes it’s proxying on behalf of the legitimate workload, but it has no way to prove that.

Why Namespaces and Sidecars Aren’t a Security Boundary

Even when containers run in separate namespaces, Kubernetes pods often share:

  • Network namespace (e.g., localhost is shared)
  • PID namespace (sometimes)
  • Volumes and secrets (occasionally)

This means:

  • Even "unprivileged" containers can talk to the sidecar.
  • Rootless containers are not always enforced.
  • Sidecar boundary is not a security boundary.

Towards Workload-Bound Identity

Closing this gap requires cryptographic identity tied to the actual process, not just the pod or the network path.

To close this gap, what we propose:

  • Using identity attestation agents inside the process boundary.
  • Leveraging kernel based TLS to bind process to cryptographic material.
  • Applying SPIFFE to issue identity per process using selectors (e.g., PID, Cgroup, etc).

This results in:

  • Cryptographic identity that is bound to the actual process, not the network path.
  • mTLS termination in-process, removing reliance on external sidecar boundaries.

Conclusion

Sidecar-based mTLS brings convenience, but also risk. It allows any co-located process to speak as the workload, with no cryptographic attestation at the process level. In a true zero-trust architecture, you must authenticate the process, not a proxy in front of it.

To build secure-by-default systems:

  • Treat sidecars as a transport layer, not a security boundary.
  • Move toward cryptographic identities tied to processes and kernel enforcement.
  • Design for explicit attestation and auditable identity paths.

Non-human identity is too foundational and too sensitive to be bolted on as an afterthought. It deserves a native, first-class treatment.

By operating directly in the Linux kernel, Riptides removes layers of complexity and guesswork, grounding identity in the one place all workloads truly run. No proxies, no sidecars, no credential sprawl just cryptographic trust, bound to the process itself. In an era of lateral movement and advanced threats, network identity isn’t enough. Process identity is the new perimeter.

The future of identity isn't just more secure. It's leaner, simpler, and built in from the start. And with Riptides, it’s already here.

Share this post
spiffe
x509
mtls
istio

Ready to replace secrets
with trusted identities?

Build with trust at the core.