env -i or sudo, and an install script with its own HTTP client never reads it. Kernel enforcement closes that gap on Linux. The kernel sends every TCP connection to ports 80 and 443 from every eligible process to the PMG proxy. A process cannot opt out.
This page covers a Linux host you operate: a VM, a shared build machine, or a self-hosted CI runner for GitHub Actions, GitLab, CircleCI, Jenkins, or any other CI system. It also covers the containers that host starts. For GitHub hosted runners, the safedep/pmg action does these steps for you. See PMG in GitHub Actions.
Kernel enforcement and the container redirect are in PMG v0.31.0 and later. Kernel enforcement is Linux only. On macOS and Windows,
pmg proxy start --enforce fails with an error that names the platform.Requirements
- Linux 5.15 or later with kernel BTF (
CONFIG_DEBUG_INFO_BTF) and cgroup v2. - Root. Attaching the kernel programs needs
CAP_BPF,CAP_NET_ADMIN, andCAP_PERFMON. - The PMG CA in the system trust store. Install it with
sudo pmg setup cert install --system. The daemon refuses to start without it. - For containers: nf_tables and conntrack. Every Docker host has them.
pmg setup doctor to check whether a host can enforce. The Kernel enforcement line names what is missing.
Enforce on a Linux host
Everypmg proxy command runs with sudo and an explicit --state path, because sudo resets HOME.
1
Install the PMG CA into the system trust store
/etc/safedep/pmg/ with a root-owned key and installs the certificate into the system store.2
Start the daemon with enforcement
--enforce-namespaces redirect to cover containers too. See Containers.3
Export the trust variables
NODE_USE_SYSTEM_CA=1, UV_NATIVE_TLS=1, REQUESTS_CA_BUNDLE, and PMG_CA_BUNDLE. Put them in the environment of the processes that install packages. On a CI runner, that is the runner’s environment file.4
Check the status
5
Stop the daemon
Run the daemon as a service
On a host that stays up, such as a self-hosted runner, asystemd unit starts the daemon at boot and restarts it on failure. The PMG repository ships an example unit. It runs the daemon as root, keeps the state file under /run/pmg, and starts before the runner service, so the runner’s own connections are enforced too.
- Install the PMG CA as root:
sudo pmg setup cert install --system. - Put the policy in
/etc/safedep/pmg/config.yml, withproxy.server.listen_portfixed andproxy.server.enforce.enabled: true. - Install and start the unit:
sudo cp pmg-proxy.service /etc/systemd/system/ && sudo systemctl enable --now pmg-proxy. - Give the runner the trust variables from
pmg proxy envthrough its environment file, such as the.envfile of a GitHub Actions runner.
pmg proxy status shows that it still enforces.
CI runners
Do not exempt the runner. Its traffic to the CI service goes through the proxy, which passes it through with the real certificate. The user that runs the jobs can write the runner’s folder, so an exemption would let a job put any program there under an exempt name and reach a registry directly. Set a job timeout on every enforced job. If the daemon stops serving but keeps running, the runner cannot report, and the job hangs until the CI system cancels it. A self-hosted runner is then offline until the daemon restarts.Restart=on-failure does not restart a hung daemon.
Set the policy
Every process is eligible unless the policy says otherwise. Only the daemon’s own process is exempt. Thepmg binary is not, so PMG_INSECURE_INSTALLATION=true pmg npm install cannot bypass the daemon.
Every key has a flag on
pmg proxy start and a PMG_* variable, for example --enforce-exempt-executable and PMG_PROXY_SERVER_ENFORCE_EXEMPT_EXECUTABLES. A list flag adds to the list in the file. See the policy table in the PMG repository.
Containers
A container has its own network namespace, so the kernel programs do not see its connections. Its traffic enters the host through a bridge, and PMG can redirect it there. Setnamespaces.mode or the --enforce-namespaces flag:
redirectturns the redirect on. The start fails when the host cannot redirect.autoturns it on where the host can, and runs asignoreelsewhere.pmg proxy statusshows the reason.ignoreis the default. Containers are not enforced.
docker run, RUN steps in docker build with the default builder and with a docker-container builder, and containers that a CI job starts. The daemon adds 169.254.200.1 to lo, listens on it, and loads one nftables table named pmg. A rule on each ingress interface, docker0 and br-* by default, sends TCP to the enforced ports to that listener. The kernel deletes the table when the daemon exits.
Trust inside a container
The redirect is transparent. Trust is not. The proxy terminates a connection to a registry host with the PMG CA, and a container that does not trust the CA fails the TLS handshake. The daemon log names the fix. Every other host keeps its real certificate. Pass the file thatPMG_CA_BUNDLE names into the container. It holds the PMG CA and the public roots. NODE_EXTRA_CA_CERTS adds to the container’s own trust. A tool that replaces its bundle, through SSL_CERT_FILE, REQUESTS_CA_BUNDLE, PIP_CERT, or CURL_CA_BUNDLE, needs this full bundle.
- docker run
- docker build
Verify
Run these on a Linux machine with Docker before you turn enforcement on for real jobs. Start the daemon with the container redirect on, then run each command from another terminal.-
A host process is enforced. Without proxy variables,
curlstill reaches the registry through the proxy. -
A container that connects to a host that is not a registry passes through. It needs nothing.
-
A container that connects to a registry without the PMG CA fails closed.
-
With the bundle mounted, the registry works through the proxy, and a known malicious test package is blocked.
sudo nft list table inet pmg shows the redirect rules while the daemon runs.
Coverage and limits
What the kernel routes:
Known limits:
- The proxy decides by host name. A redirected TLS connection without SNI, or with Encrypted ClientHello, and a plain HTTP request without a
Hostheader are dropped. A registry that clients reach by IP needs a name, or askip_destinationsentry so the kernel never redirects it. - A client that pins certificates fails closed on registry hosts.
- Node 20 cannot read the system trust store and is not supported under enforcement. Node 22 and later work with
NODE_USE_SYSTEM_CA=1. - An exemption covers a file, not the code that runs in it. Any process can start an exempt program with
LD_PRELOADand run its own code in it. Keep the exempt list short. sudobypasseseligible_users, as described in Set the policy.- One daemon enforces one cgroup. A second
pmg proxy start --enforceon the same cgroup fails. - The daemon runs as root for its whole life.
PMG in GitHub Actions
Enforce on GitHub hosted runners with one action input.
PMG System Install
Protect every user on a shared Linux host or in a Docker image with PATH shims.
Persistent proxy reference
How the kernel programs and the container redirect work, with every policy key.
PMG
How PMG blocks malicious packages at install time.

