auditing-init-and-sidecar-injection-trust · git:20260828.ce55026 · 2026-08-28 · sha256 3a2cd87dca73a0c7

auditing-init-and-sidecar-injection-trust git:20260828.ce55026A

Immutable. This exact content is served forever at /api/v1/blob/3a2cd87dca73a0c7.

---
name: auditing-init-and-sidecar-injection-trust
description: >-
  Audit the init and sidecar containers a workload runs, including ones injected by a mutating admission
  webhook, for trust the main container never granted: an injected sidecar that runs with broader privileges,
  host access, or credentials than the workload, an init container that fetches and executes remote content
  before the app starts, a shared volume or process namespace that lets a sidecar read the main container's
  secrets, and an injection whose image and configuration come from a source the workload owner does not
  control. Covers Kubernetes pods where init and sidecar containers, declared or webhook-injected, share the
  pod with the application. Use when pods run init or sidecar containers, especially injected ones. The
  injected or auxiliary container is the source, the pod resource or credential it reaches is the sink, and
  the trust it holds beyond the main container is the bug.
license: MIT
---

# Auditing init and sidecar injection trust: the containers you did not write share your pod

A pod is not just its application container. Init containers run first, sidecars run alongside, and many are
injected automatically by a mutating admission webhook that the workload owner never sees in their manifest.
All of them share the pod: the same network namespace, often shared volumes, sometimes the process namespace,
and they can be granted their own security context and credentials. That makes every init and sidecar
container a trust question the main container did not ask. An injected sidecar may run privileged or with host
access the app never needed; an init container may fetch and execute remote content before the app starts; a
shared secret volume or process namespace lets a sidecar read the application's secrets; and the injected
image and its configuration may come from a source outside the workload owner's control. The pod looks like
one workload but is a collection of containers with different privileges and origins. You audit this by
enumerating every init and sidecar container, declared and injected, and checking what trust each holds.

## When to use

- Pods run init or sidecar containers, especially ones injected by a mutating admission webhook.
- An injected or auxiliary container may run with broader privilege, host access, or credentials than the app.
- Init containers fetch or execute content, or sidecars share volumes or namespaces with the main container.

## Scope check

Audit init and sidecar trust only on clusters and workloads you own or are authorized to assess, on
non-production pods. Confirming a sidecar can read the app's secrets or that an init container executes remote
content touches real workloads, so use non-production pods and do not exfiltrate anything you surface. If you
can't name the authorization, stop.

## The loop

1. **Establish the workload's intended trust first.** Name what the application container is supposed to run
   with: its privilege level, its credentials, its host access. This is the false-positive killer: a pod whose
   init and sidecar containers run at or below the app's privilege, from controlled images, sharing nothing
   sensitive, is fine. Name the intended trust, then check each auxiliary container against it.

2. **Enumerate every init and sidecar container, including injected ones.** List the containers actually in the
   pod at runtime, not just those in the authored manifest, since a mutating webhook may add sidecars. For each,
   note its image source, security context, credentials, and mounts. An injected container the owner did not
   declare is the one most likely to hold unexpected trust.

3. **Compare each auxiliary container's privilege to the app.** For each init and sidecar container, check
   whether it runs privileged, adds capabilities, shares a host namespace, or mounts host paths that the main
   container does not. A sidecar with broader privilege than the app raises the pod's whole blast radius to that
   sidecar's level.

4. **Check init containers that fetch or execute content.** For each init container, determine whether it
   downloads and runs remote content, applies configuration from an external source, or executes a script
   before the app starts. An init container that pulls and executes untrusted content runs attacker-influencable
   code in the pod before the application even begins.

5. **Check shared volumes and namespaces for secret reach.** Determine which volumes and namespaces the
   auxiliary containers share with the main container. A sidecar that mounts the app's secret volume or shares
   its process namespace can read the application's secrets and memory. Confirm sensitive mounts and namespaces
   are not shared with a less-trusted sidecar.

6. **Confirm and record.** Confirm by showing an init or sidecar container holds trust the app did not grant: a
   sidecar reading the app's secret, an injected container running privileged, or an init container executing
   remote content, on non-production pods and without exfiltrating. Kill the lead if every init and sidecar
   container, declared and injected, runs at or below the app's privilege from a controlled image, shares no
   sensitive volume or namespace, and executes no untrusted content. Record the auxiliary container source, the
   pod resource or credential sink, and the trust it held beyond the main container.

## Where init and sidecar trust leaks

- **Injected sidecars are invisible in the manifest.** A mutating webhook adds containers the owner never
  declared, so the authored spec understates the pod's trust.
- **A sidecar can out-privilege the app.** A sidecar running privileged or with host access raises the pod's
  blast radius above the application's own security context.
- **Init containers can fetch and execute.** An init container that pulls and runs remote content executes
  attacker-influencable code before the app starts.
- **Shared volumes and namespaces expose secrets.** A sidecar that mounts the app's secret volume or shares its
  process namespace reads the application's secrets and memory.
- **Injected images come from elsewhere.** The injected image and its configuration may originate from a source
  the workload owner does not control or verify.

## Worked example (a confirm and a kill)

> **Confirm.** A mutating webhook injects a sidecar into every pod in a namespace. The injected sidecar runs
> privileged and mounts the application's secret volume, and its image comes from a registry the workload owner
> does not control. From the sidecar, a process reads the application's database credential the app never shared
> with it. **Confirmed** injected-sidecar trust beyond the workload, `high`, remediation = scope the injected
> sidecar to the minimum privilege it needs, stop it from mounting the app's secret volume, and pin and verify
> the injected image from a controlled source.
>
> **Kill.** Every init and sidecar container in the pod, including the webhook-injected ones, runs unprivileged
> at or below the app's security context from pinned, verified images the owner controls, none mounts the
> application's secret volume or shares its process namespace, and no init container fetches or executes remote
> content. No auxiliary container holds trust the app did not grant. **Killed**, `kill_reason` = "all init and
> sidecar containers run at or below app privilege from controlled images with no shared secret volume or
> namespace and no remote execution; no injected container exceeds the workload's trust."

## Rationalizations to reject

- *"The manifest only has one container."* → A mutating webhook may inject more at runtime; enumerate the
  containers actually in the pod, not just the authored spec.
- *"The sidecar is from the platform team."* → Confirm its privilege, image source, and mounts; a trusted team's
  sidecar can still out-privilege the app or read its secrets.
- *"Init containers just set things up."* → If an init container fetches and runs remote content, it executes
  code in the pod before the app; check what it pulls and runs.
- *"They are in the same pod, sharing is fine."* → Sharing a secret volume or process namespace lets a
  less-trusted sidecar read the app's secrets; scope what is shared.
- *"The injected image is standard."* → Confirm it is pinned and from a source you verify; an injected image
  from elsewhere runs in your pod with whatever trust it is granted.

## Executing this in practice

You need the full runtime list of init and sidecar containers including injected ones, each container's image
source, security context, credentials, and mounts, whether any init container fetches or executes content, and
the shared volumes and namespaces. For each auxiliary container, compare its trust to the application's. Reading
the runtime pod spec and the mutating webhook configuration shows the granted trust; showing a sidecar reach the
app's secret or an init container execute remote content shows whether the boundary holds.

## Related

- `hunting-container-escape-surface` - the privilege and host-access settings this skill checks on auxiliary
  containers are the same escape surface, viewed per injected container.
- `auditing-admission-control-policy-gaps` - the mutating webhook that injects sidecars is admission machinery;
  a gap there is how an untrusted injection gets in.
- `auditing-workload-secret-exposure-surface` - the shared-volume secret reach a sidecar exploits is that
  skill's subject, here caused by an injected neighbor.
- `auditing-container-image-provenance` - the injected sidecar's image provenance question; an unverified
  injected image runs in your pod.
- [FINDING-SCHEMA.md](../../FINDING-SCHEMA.md) - source = the injected or auxiliary container, sink = the pod
  resource or credential it reaches, evidence = the trust it held beyond the main container.