Skip to content

orthrus: path-normalization order differs between backend and agent muzzle filters #1160

Description

@Wikid82

Summary

backend/internal/orthrus/muzzle.go and agent/muzzle/muzzle.go are two independent Docker API allowlist filters enforcing the same read-only policy at two different points in the Orthrus tunnel (Charon-side reverse proxy, and the remote agent binary right before it touches the real Docker socket). They normalize incoming request paths in a different order before matching:

  • Backend (muzzle.go): strips the /vX.Y version prefix first, then runs path.Clean.
  • Agent (agent/muzzle/muzzle.go): runs path.Clean first, then strips the version prefix.

A synthetic crafted input (e.g. /foo/../v1.44/images/x/json) can normalize to a different result depending on which order is applied.

Why this isn't an active bug today

The backend muzzle always runs first in the real request pipeline (Charon proxies the request before it ever reaches the tunnel), so it already blocks the one input shape that exposes the divergence before the agent's filter is reached. Confirmed via Supervisor review during the Orthrus external-proxy hotfix (see commits 98a68b67, b71cbd62, eabf358d).

Why it's worth fixing anyway

Two files meant to enforce identical security policy should behave identically in isolation, not rely on one always running before the other. If the request path into the agent's filter ever changes (e.g. a future direct-to-agent access path, or a refactor that reorders backend proxying), this asymmetry could become exploitable without anyone noticing, since neither file's tests currently assert the two filters agree on edge-case inputs.

Suggested fix

Align the normalization order in both files (recommend: strip version prefix, then path.Clean, matching the backend's current order), and add a shared test fixture / property-based test that feeds the same corpus of inputs to both Muzzle.ServeHTTP (backend) and Filter.Allow (agent) and asserts identical accept/reject decisions.

Related

Discovered while fixing namespaced-image support in both muzzle filters for the Orthrus External Docker Proxy feature — see docs/reports/qa_report.md and docs/plans/current_spec.md for full context.

Metadata

Metadata

Assignees

No one assigned

    Labels

    architectureSystem design and structurebackendServer-side codelowFuture enhancement, not urgentsecuritySecurity-related

    Projects

    Status
    In Progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions