Hello,
I am writing to share details regarding a seccomp filter bypass pattern affecting several projects (including containerd, Podman, systemd, and QEMU) that rely on denylists for system call argument inspection.
The issue stems from an evaluation mismatch between seccomp-bpf and the Linux kernel when 32-bit integer arguments are passed via 64-bit CPU registers on 64-bit architectures.
Vulnerability Details =====================
Many system calls accept 32-bit integers as arguments. For example, the first argument to socket(2) (the address family/domain) is an 'int'. On 64-bit architectures, this argument is loaded into a 64-bit register.
When handling the system call, the kernel implicitly ignores or truncates the upper 32 bits. However, seccomp filters inspect the full 64-bit register value unless an explicit mask is applied.
When a seccomp profile implements a denylist for a specific argument value, an attacker can bypass the filter by setting non-zero bits in the upper 32 bits of the register:
1. A seccomp rule attempts to block socket creation for AFVSOCK (0x28) by matching on (arg0 == 0x28). 2. The caller passes 0x100000028 in the corresponding 64-bit register. 3. Seccomp evaluates (0x100000028 == 0x28), which evaluates to false. The denylist rule is not triggered, and seccomp allows the syscall. 4. The kernel receives the syscall, casts/truncates the argument to a 32-bit int (0x28), and creates the AFVSOCK socket.
Impact ======
Among the projects reviewed, systemd was the most significantly affected (see issue #44134). While RestrictAddressFamilies= allowed bypassing socket family restrictions, the impact on RestrictNamespaces= is particularly critical.
RestrictNamespaces= relies on seccomp to prevent services from creating or joining namespaces via unshare(2), clone(2), and setns(2). Because 32-bit flag arguments were matched without masking upper register bits, denylist configurations could be bypassed.
Remediation ===========
To prevent this bypass:
1. Argument Masking: Filters must mask 32-bit arguments to their low 32 bits before evaluating them (e.g., using SCMPCMPMASKEDEQ in libseccomp).
2. Allowlists over Denylists: Avoid denylists for system call arguments. Enforcing a strict default-deny policy with an allowlist of valid 64-bit values inherently prevents unexpected upper-bit payloads.
Documentation patches addressing this pitfall have been submitted across the libseccomp C, Go, and Rust bindings.
Background and Tooling ======================
This behavior was identified during seccomp profile analysis using seccat (a tool converting seccomp JSON to/from a compact DSL) and secprobe (a non-destructive rule testing utility leveraging seccompunotify(2) to inspect syscalls without executing them).
https://github.com/ricardobranco777/seccat
An improvement to seccomp-tools was suggested: https://github.com/david942j/seccomp-tools/issues/407
Affected Projects and References ================================
- containerd: https://github.com/containerd/containerd/issues/14348
- Podman (container-libs): https://github.com/podman-container-tools/container-libs/issues/1248
- QEMU: https://gitlab.com/qemu-project/qemu/-/workitems/4671
- systemd: https://github.com/systemd/systemd/issues/44134 https://github.com/systemd/systemd/issues/44148
Best regards, Ricardo Branco
This is a vulnerability report sent to us through https://issues.redhat.com/browse/PSIRTSUPT-20013 and was created using the PoC auto-triage agents. It contains hints on the vulnerability extracted by the IA and the full report. ALWAYS review it before any action. Once working on this, don't forget to also update the JSM ticket.
A flaw was found in Podman 5.8.x. The 'podman quadlet install --replace' command opens the existing destination file with OCREATE|OWRONLY but omits OTRUNC. When the initial reflink copy attempt fails (common on non-reflink-capable filesystems including many RHEL default XFS configurations), the fallback in ReflinkOrCopy uses io.Copy which performs a non-truncating write. If the replacement Quadlet file is shorter than the original, trailing bytes from the old file — including security-sensitive directives such as Volume= host-access mounts — survive in the installed unit file. The command returns success with no warning.
After a systemd daemon-reload or reboot, these stale directives reactivate host access the administrator explicitly revoked. A subsequent mutable-tag container image pull by an adversarial image can then exploit the retained host-access mounts to read secrets, modify files, or disrupt host services.
The vulnerable code paths are in pkg/domain/infra/abi/quadlet.go (lines 338-360, OCREATE|OWRONLY without OTRUNC) and vendor/go.podman.io/storage/pkg/fileutils/reflinklinux.go (lines 12-19, non-truncating io.Copy fallback).
Upstream fix: Podman 6.0/main branch introduced an atomic temp-file-plus-rename replacement pattern via PRs #28335 (merged 2026-06-05) and #28860 (merged 2026-06-25). The maintained 5.8 branch remains unpatched.
Mitigation: Administrators using 'podman quadlet install --replace' should manually verify the installed unit file contents after each replacement operation, and avoid using --replace with shorter replacement files until a fix is available. Alternatively, manually remove the destination file before running 'podman quadlet install' (without --replace).
This is a vulnerability report sent to us through https://issues.redhat.com/browse/PSIRTSUPT-20013 and was created using the PoC auto-triage agents. It contains hints on the vulnerability extracted by the IA and the full report. ALWAYS review it before any action. Once working on this, don't forget to also update the JSM ticket.
A flaw was found in Podman 5.8.x. The 'podman quadlet install --replace' command opens the existing destination file with OCREATE|OWRONLY but omits OTRUNC. When the initial reflink copy attempt fails (common on non-reflink-capable filesystems including many RHEL default XFS configurations), the fallback in ReflinkOrCopy uses io.Copy which performs a non-truncating write. If the replacement Quadlet file is shorter than the original, trailing bytes from the old file — including security-sensitive directives such as Volume= host-access mounts — survive in the installed unit file. The command returns success with no warning.
After a systemd daemon-reload or reboot, these stale directives reactivate host access the administrator explicitly revoked. A subsequent mutable-tag container image pull by an adversarial image can then exploit the retained host-access mounts to read secrets, modify files, or disrupt host services.
The vulnerable code paths are in pkg/domain/infra/abi/quadlet.go (lines 338-360, OCREATE|OWRONLY without OTRUNC) and vendor/go.podman.io/storage/pkg/fileutils/reflinklinux.go (lines 12-19, non-truncating io.Copy fallback).
Upstream fix: Podman 6.0/main branch introduced an atomic temp-file-plus-rename replacement pattern via PRs #28335 (merged 2026-06-05) and #28860 (merged 2026-06-25). The maintained 5.8 branch remains unpatched.
Mitigation: Administrators using 'podman quadlet install --replace' should manually verify the installed unit file contents after each replacement operation, and avoid using --replace with shorter replacement files until a fix is available. Alternatively, manually remove the destination file before running 'podman quadlet install' (without --replace).
Podman is a tool for managing OCI containers and pods. From 1.8.1 until 5.8.4, a container image that contains a environment variable with just a key and no value can trick podman into passing that variable from the host into the container. This is made worse by the fact that using an asterisk () will cause podman to pass all host variables into the container. So essentially a malicious image can exfiltrate all podman environment variables that are set in the session from where the container is launched. This vulnerability is fixed in 5.8.4 and 6.0.0.
Summary
An container image that contains a environment variable with just a key and no value can trick podman into passing that variable from the host into the container. This is made worse by the fact that using an asterisk () will cause podman to pass all host variables into the container. So essentially a malicious image can exfiltrate all podman environment variables that are set in the session from where the container is launched.
Details
podman run allows --env VAR1 or --env VAR which will read the variable values from the current environment and then passes them into the container. However because the same parsing logic was reused for the image config env section that means that an image variable could also gain access to that.
Patch
That image spec requires the env variables to be in the form of key=value, so to address this invalid formatted variables get rejected and the container will not run.
Fixed in https://github.com/podman-container-tools/podman/commit/6c431b73dbf8e4b20b778644d7a80caebdb75050
Workaround
Do not run untrusted images. Before running an image consider inspecting the config with podman image inspect --format '{{.Config.Env}}' <image> and check for any variables that do not have a value assigned.
Podman is a tool for managing OCI containers and pods. Versions 4.8.0 through 5.8.1 contain a command injection vulnerability in the HyperV machine backend in pkg/machine/hyperv/stubber.go, where the VM image path is inserted into a PowerShell double-quoted string without sanitization, allowing $() subexpression injection. Because PowerShell evaluates subexpressions inside double-quoted strings before executing the outer command, an attacker who can control the VM image path through a crafted machine name or image directory can execute arbitrary PowerShell commands with the privileges of the Podman process. On typical Windows installations this means SYSTEM-level code execution, and only Windows is affected as the code is exclusive to the HyperV backend. This issue has been patched in version 5.8.2.
The podman kube play command can overwrite host files when the kube file contains a ConfigMap or Secret volume mount and the volume already contains a symlink to a host file. This allows a malicious container to write to arbitrary files on the host but the attacker only controls the target path not the contents that will be written to file. The contents are defined in the yaml file by the end user.
Impact The podman machine init command fails to verify the TLS certificate when downloading the VM images from an OCI registry (which it does by default since 5.0.0) allowing a possible Man In The Middle attack.
Patches https://github.com/containers/podman/commit/726b506acc8a00d99f1a3a1357ecf619a1f798c3 Fixed in v5.5.2
Workarounds Download the disk image manually via some other tool that verifies the TLS connection. Then pass the local image as file path (podman machine init --image ./somepath)
A flaw in the containers/common Go library, used by container runtimes such as Podman, Buildah, and CRI-O, allows a malicious container image to exploit the FIPS mode to bind mount arbitrary host directories into the container. The flaw arises from the MountsWithUIDGID() function, which attempts to mount a FIPS-related directory inside the container but does not properly verify the path. If the FIPS path is a symlink, it could point to arbitrary directories on the host, allowing an attacker to access sensitive host files.
Summary: We received a report of an attack vector on containers which share an IPC namespace (definitely Podman, but likely also applicable to Kubernetes, Docker, and other container runtimes). At least two containers are configured with a shared IPC namespace and a cgroup limiting memory. One of those containers is malicious, and contains a binary which creates a large number of IPC resources in /dev/shm, and continues doing so until it is OOM killed. The malicious container is now dead, its cgroup removed, but the IPC resources it created are not; they are tied to the IPC namespace that will not be removed until all containers using it are stopped, and one non-malicious container is holding the namespace open. The malicious container is restarted (either automatically or by attacker control), repeating the process and increasing the amount of memory consumed. With a container configured to restart always (e.g. podman run --restart=always) this results in a memory-based denial of service of the system.
Podman Version: Version 5.0.0-dev and before