Skip to content

fix(security): confine CRI localhostProfile seccomp path to the seccomp root (LOW) - #143

Merged
ZhiXiao-Lin merged 1 commit into
mainfrom
fix/cri-seccomp-path-confine
Jun 17, 2026
Merged

fix(security): confine CRI localhostProfile seccomp path to the seccomp root (LOW)#143
ZhiXiao-Lin merged 1 commit into
mainfrom
fix/cri-seccomp-path-confine

Conversation

@ZhiXiao-Lin

Copy link
Copy Markdown
Contributor

Severity: LOW (arbitrary host-file open oracle via CRI)

parse_localhost_seccomp_deny read localhost_ref off the host disk with no path confinement. localhost_ref is a pod's securityContext.seccompProfile.localhostProfileattacker-settable by anyone who can create pods — so it was an arbitrary host-file open primitive (path-traversal / file-existence oracle).

Rated LOW (not the HIGH the finder first proposed): information disclosure is refuted — the parse error is only tracing::warn-logged, never returned to the gRPC caller, and content only escapes as syscall names from valid OCI-seccomp JSON into the attacker's own container. But the missing guard is real.

Fix

confined_seccomp_path mirrors kubelet/containerd semantics:

  • resolve the ref under the configured seccomp root (default /var/lib/kubelet/seccomp, override A3S_BOX_SECCOMP_PROFILE_ROOT),
  • reject any .. component,
  • require an absolute ref to lie within the root.

An out-of-root or traversing ref is rejected and the caller falls back to RuntimeDefault (never unconfined).

Test (TDD + neuter-verified)

confines_localhost_profile_to_root_and_rejects_traversal — accepts in-root relative/absolute refs; rejects ../../etc/passwd, sub/../../escape, /etc/passwd, /etc/shadow, /var/lib/kubelet/seccomp-evil/x (prefix-confusion). Neuter-verified on the KVM server (disabling the root check makes it FAIL on /etc/passwd); fmt + clippy clean.

Completes the untrusted-input security audit (4/4)

After #141 (CRITICAL digest path-traversal), #142 (HIGH/MED decompression bombs), #140 (HIGH whiteout host-file deletion).

…mp root

LOW. `parse_localhost_seccomp_deny` did `std::fs::read_to_string(localhost_ref)`
with no path confinement. `localhost_ref` is the pod's
`securityContext.seccompProfile.localhostProfile` — attacker-settable through the
CRI by anyone who can create pods — so it was an arbitrary host-file OPEN
primitive (a path-traversal / file-existence oracle). Information disclosure is
limited (the parse error is only warn-logged, never returned to the gRPC caller,
and content only escapes as syscall names from valid OCI-seccomp JSON into the
attacker's own container), hence LOW — but the missing guard is real.

Fix: `confined_seccomp_path(localhost_ref, root)` rejects any `..` component and
requires an absolute ref to lie within the seccomp root; a relative ref resolves
under it. The root is injected (default /var/lib/kubelet/seccomp via
`seccomp_profile_root()`, override A3S_BOX_SECCOMP_PROFILE_ROOT) so the check is
testable without process-global env. An out-of-root/traversing ref is rejected
and the caller falls back to RuntimeDefault (never unconfined).

Tests: new confines_localhost_profile_to_root_and_rejects_traversal (rejects
`../../etc/passwd`, `/etc/passwd`, prefix-confusion, etc.); the two existing
parse_localhost_seccomp_deny tests now pass their tempdir as the root. Full
a3s-box-cri lib suite (250) green; neuter-verified (disabling the root check
makes the new test FAIL on /etc/passwd); fmt + clippy clean.

Completes the untrusted-input security audit (4/4): after #141 (CRITICAL digest
traversal), #142 (HIGH/MED bombs), #140 (HIGH whiteout deletion).
@ZhiXiao-Lin
ZhiXiao-Lin force-pushed the fix/cri-seccomp-path-confine branch from 28b8fac to 27c1165 Compare June 16, 2026 14:12
@ZhiXiao-Lin
ZhiXiao-Lin merged commit ad26f69 into main Jun 17, 2026
8 checks passed
@ZhiXiao-Lin
ZhiXiao-Lin deleted the fix/cri-seccomp-path-confine branch June 17, 2026 02:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant