rfxn-defense

Latest: v3.0.2 EL7 / EL8 / EL9 / EL10 x86_64 7 LPE classes 4-hourly auto-update GPL v2

Responsive defense layer for Linux. Ships kernel-LPE mitigations as 0days land, closing the window between public CVE disclosure and the vendor patch reaching your hosts (or a fleet reboot becoming available). Signed yum/dnf repo for EL7/EL8/EL9/EL10, 4-hourly auto-update cron, zero reboot required for any mitigation. New bug classes ship with each release. Install once, stay covered.

Today's shipping coverage: 7 LPE classes across two families. Copy Fail page-cache writes (cf1 / CVE-2026-31431, cf2 / Dirty Frag-ESP / CVE-2026-43284, DF-RxRPC / CVE-2026-43500, Fragnesia, PinTheft / CVE-2026-43494, DirtyDecrypt / CVE-2026-31635); FD-theft via SUID exit-race (ssh-keysign-pwn / CVE-2026-46333). See coverage matrix for per-class rung detail.

Six defense-in-depth rungs in one dnf install: LD_PRELOAD shim, modprobe blacklists, per-unit systemd drop-ins, host-wide userns + ptrace + io_uring sysctls, auditd tripwires, and a read-only posture auditor. Auto-detection at install time suppresses any drop-in that would break a detected workload (IPsec, AFS, rootless containers, Flatpak, firejail, desktop browsers, Oracle RDS / HPC, io_uring consumers); every other layer stays active.

Upgrading from v2.x (copyfail-defense) or v1.x (afalg-defense)? sudo dnf upgrade -y rfxn-defense handles every prior layout (rename, file splits, new subpackages) automatically. State under /var/lib/copyfail-defense/ and /etc/copyfail/ migrates to the rfxn-defense paths via %pretrans mv -n (idempotent). SIEM queries must update the audit-key prefix (copyfail_*rfxn_*). Review journalctl -t rfxn-defense-detect afterward to see what was suppressed. Shim activation remains the explicit operator step (rfxn-shim-enable).
Legacy URL hosts need manual migration. GitHub Pages does not redirect renamed-repo URLs. v2.x hosts with copyfail.repo in /etc/yum.repos.d/ will 404 on dnf check-update after v3.0.0 ships:
sudo curl -sSL https://rfxn.github.io/rfxn-defense/rfxn-defense.repo \
    -o /etc/yum.repos.d/rfxn-defense.repo
sudo rm -f /etc/yum.repos.d/copyfail.repo
sudo dnf upgrade -y rfxn-defense

Install

A single rfxn-defense.repo file works for EL7/EL8/EL9/EL10: dnf expands $releasever + $basearch per host. RPMs are GPG-signed and the metadata itself is verified via detached repomd.xml.asc (gpgcheck=1 + repo_gpgcheck=1).

sudo curl -sSL https://rfxn.github.io/rfxn-defense/rfxn-defense.repo \
  -o /etc/yum.repos.d/rfxn-defense.repo
sudo dnf install -y rfxn-defense
sudo /usr/sbin/rfxn-shim-enable

The 4-hourly auto-update cron (-autoupdate subpackage, pulled by the meta) keeps the host current; new mitigations land within 4 hours of a release tag with no operator action. Opt out by touching /etc/rfxn-defense/auto-update.disabled.

The meta pulls seven subpackages (-audit as soft dep on EL8/9/10, hard dep on EL7 since rpm-4.11 has no Recommends:):

SubpackageCoverage
rfxn-defense-shim LD_PRELOAD AF_ALG block (cf1 primary)
rfxn-defense-modprobe kernel-module entry-point cuts (cf1, cf2, Dirty Frag, PinTheft, DirtyDecrypt)
rfxn-defense-systemd per-unit RestrictAddressFamilies=~AF_ALG AF_KEY AF_RXRPC AF_RDS + RestrictNamespaces=~user net on user@/sshd/cron/crond/atd; container-runtime + RDS opt-in examples (v3.0.1 fixed deny-list syntax: only the first token carries the ~)
rfxn-defense-sysctl host-wide user.max_user_namespaces=0 (suppressed on rootless / Flatpak / firejail / browser); kernel.yama.ptrace_scope=2 (always-applied independent drop-in since v3.0.1); kernel.io_uring_disabled=2 (Linux 6.6+ only, suppressed on io_uring workloads)
rfxn-defense-auditor read-only host posture auditor (rfxn-local-check) covering 7 bug classes with per-class layer breakdown
rfxn-defense-audit auditd tripwires (rfxn_afalg/afkey/afrxrpc/afrds/pidfd_getfd)
rfxn-defense-autoupdate /etc/cron.d/rfxn-defense-autoupdate + flock-protected /usr/sbin/rfxn-defense-update wrapper

Coverage matrix

Which rung blocks which bug class. = primary mitigation, applied without caveat;  n = active coverage with a kernel- or workload-conditional caveat (see footnote); n alone = detection only, no mitigation (see footnote); · = not applicable.

Mitigation rungcf1cf2DF-ESPDF-RxRPC 6FragnesiaPinTheftkeysign-pwn
LD_PRELOAD shim (AF_ALG hook) · ·✓ ¹ · ··
modprobe algif_aead family ✓ ²· ·· · ··
modprobe esp4 esp6 xfrm_user xfrm_algo · · ··
modprobe rxrpc ·· · · ··
modprobe rds rds_tcp rds_rdma ·· ·· · ✓ ⁴·
systemd RestrictAddressFamilies=~AF_ALG · ·· · ··
systemd RestrictAddressFamilies=~AF_KEY · · ··
systemd RestrictAddressFamilies=~AF_RXRPC ·· · · ··
systemd RestrictAddressFamilies=~AF_RDS ·· ·· · ·
systemd RestrictNamespaces=~user ~net · · ··
sysctl user.max_user_namespaces=0 · · ··
sysctl kernel.yama.ptrace_scope=2 (always-on, v3.0.1) ·· ·· · ·
sysctl kernel.io_uring_disabled=2 ·· ·· · ✓ ⁵·
auditd tripwire rules ³³ ³³ ³ ³³

1 Catches the cksum step in the public DF-RxRPC PoC, not the kernel sink itself; defense-in-depth, not a primary stop.
2 No-op on RHEL stock kernels (CRYPTO_USER_API* built-in). Supported workaround: grubby --update-kernel ALL --args "initcall_blacklist=algif_aead_init" + reboot.
3 Detection only, not mitigation. Telemetry for socket(AF_ALG/AF_KEY/AF_RXRPC/AF_RDS) and pidfd_getfd from unprivileged users. Highest value on hosts where modprobe blacklists are auto-suppressed (IPsec / AFS / Oracle RDS workloads) and the kernel sink stays reachable. Query via ausearch -k rfxn_{afalg,afkey,afrxrpc,afrds,pidfd_getfd}.
4 Functional on Ubuntu/Debian/Arch kernels and ELRepo kernel-ml swaps where rds.ko is loadable. No-op on stock RHEL/Alma/Rocky/Oracle UEK kernels (no CONFIG_RDS=m). Auto-suppressed on Oracle Grid / HPC hosts (signals: /etc/oratab, crsctl, loaded rds*.ko).
5 Auto-applied on Linux 6.6+ hosts where no io_uring workload is detected (liburing.so in /proc/*/maps, known-consumer binaries, io_uring-named systemd units). Suppressed on rootless / Flatpak / container-runtime hosts and kernels < 6.6. Override: CFD_FORCE_IOURING_DISABLE=1 rfxn-redetect or CFD_SUPPRESS_IOURING_DISABLE=1 rfxn-redetect.
6 DirtyDecrypt (CVE-2026-31635, rxgk_* RXGK token-decrypt in-place crypto) is cross-stamped onto the DF-RxRPC column: every AF_RXRPC mitigation that covers DF-RxRPC also covers DirtyDecrypt.

Audit keys (-audit subpackage)

KeySignature
rfxn_afalg socket(AF_ALG=38) by unprivileged user (cf1)
rfxn_afkey socket(AF_KEY=15) by unprivileged user (cf2 / DF-ESP / Fragnesia)
rfxn_afrxrpc socket(AF_RXRPC=33) by unprivileged user (DF-RxRPC / DirtyDecrypt)
rfxn_afrds socket(AF_RDS=21) by unprivileged user (PinTheft)
rfxn_pidfd_getfd pidfd_getfd() syscall 438 by unprivileged user (ssh-keysign-pwn)

Rules ship at /etc/audit/rules.d/99-rfxn-defense.rules with auid≥1000 filter on every key. The auditor probes page-cache integrity for /usr/bin/su, /usr/libexec/openssh/ssh-keysign, and the PAM stacks each class targets, as a cached-IOC for an in-flight exploit. See --json posture.bug_classes[*].kernel_sink.

Operator-applied (auditor-recommended)

Flagged via --emit-remediation; no subpackage applies them, since each can break legitimate workloads on a busy fleet. Review before pasting.

ActionTargetsWhen recommended
chmod 4750 /usr/bin/su && chgrp wheel /usr/bin/su cf2, DF-ESP Suppressed when non-wheel/admin interactive users exist (cPanel-style tenant fleets); chmod 4750 would break their su workflow.
auditd rule cf_userns (unshare(CLONE_NEWUSER)) cf2, DF-ESP Hosts where auditd is tuned for userns events (otherwise high alert noise).
auditd rule cf_addkey (add_key("rxrpc",...)) DF-RxRPC Always; rxrpc keyring activity is rare enough that the false-positive rate stays low.

Auto-detection of conflicting workloads

The installer inspects the host in %posttrans and suppresses any drop-in that would break a detected workload. Every other layer stays active. The cf1 LD_PRELOAD shim and audit tripwires are never suppressed, so cf1 (CVE-2026-31431) coverage is unchanged on every host.

Detection signals and suppression

WorkloadSignals (any of)Suppresses
IPsec (strongSwan, libreswan, openswan) enabled systemd unit (strongswan/libreswan/openswan/ipsec/pluto); /etc/ipsec.conf conn stanza; non-empty *.conf under /etc/swanctl/conf.d/, /etc/ipsec.d/, /etc/strongswan{,/conf.d}/ 99-cf2-xfrm.conf (esp4, esp6, xfrm_user, xfrm_algo blacklist). cf2/DF-ESP still blocked via the systemd RestrictNamespaces=~user ~net unshare gate.
AFS (openafs, kafs) enabled systemd unit (openafs-client/server, kafs, afsd); /etc/openafs/{CellServDB,ThisCell}; /etc/krb5.conf.d/openafs*; /proc/fs/afs/ registered 99-rxrpc.conf + 12-rxrpc-af.conf (~AF_RXRPC on all 5 tenant units). DF-RxRPC residual coverage: auditd rfxn_afrxrpc tripwire.
Rootless containers (rootless podman/buildah) /home/*/.local/share/containers/storage/overlay-containers/ (mtime ≤ 180d); /var/lib/containers/storage/overlay-{containers,images}/ or vfs-{containers,images}/ contains a non-lockfile entry (v3.0.1: tightened from "any non-empty subdir" to require a real container or image, ruling out storage-tree init by podman package install); /run/user/<UID≥1000>/containers/; podman.socket enabled (system or per-user) 15-userns.conf on user@.service only + host-wide userns sysctl. sshd/cron/crond/atd keep RestrictNamespaces=~user net. kernel.yama.ptrace_scope=2 is NOT affected (own drop-in since v3.0.1).
Userns consumers (Flatpak, firejail, desktop browser) non-empty /var/lib/flatpak/{app,runtime} or per-user ~/.local/share/flatpak/app (mtime ≤ 180d); /usr/bin/firejail; /usr/bin/{chromium,chromium-browser,google-chrome,firefox,firefox-esr} 99-rfxn-defense-userns.conf host-wide sysctl only; per-unit RestrictNamespaces stays active.
RDS workload (Oracle Grid Infrastructure, HPC) /etc/oratab non-comment non-blank entry; **/grid/bin/crsctl under /u01/app/oracle or /opt/oracle; any of /sys/module/{rds,rds_tcp,rds_rdma} currently loaded 99-rfxn-defense-rds.conf modprobe drop only; tenant-unit ~AF_RDS stays applied; rfxn_afrds auditd tripwire stays loaded.
io_uring workload liburing.so in /proc/*/maps; known consumer binary executable (postgres, scylla, mariadbd, dockerd, redis-server, nginx, envoy, rabbitmq-server); io_uring-named systemd unit 99-rfxn-defense-iouring.conf only. PinTheft primary cut (RDS modprobe) stays applied.

False-positive guards: /etc/subuid populated by useradd is not a rootless signal (shadow-utils auto-populates it for every regular user, which produced ~100% FPs on cPanel-shaped fleets in v2.0.1 rev 1). Rootful container signal requires mtime < 90d. /home walk bounded (maxdepth 6, mtime -180). /run/user/<UID>/containers requires UID ≥ 1000.

Inspect the decision

sudo cat /var/lib/rfxn-defense/auto-detect.json
sudo journalctl -t rfxn-defense-detect --since today
sudo rfxn-local-check --json | jq '.posture.auto_detect'

auto-detect.json (schema v2) lists detected.<workload>.signals, suppressed.<dropin>, and applied.<dropin> flags for every drop-in the installer manages. Detection runs in %posttrans after every install/upgrade and on demand via rfxn-redetect.

Re-detect or force full coverage

# Re-run detection after enabling IPsec/AFS/rootless post-install
sudo /usr/sbin/rfxn-redetect
sudo systemctl daemon-reload
sudo systemctl try-reload-or-restart sshd.service
sudo sysctl --system   # if any sysctl drop-in was added or removed

# Skip detection entirely - apply every drop-in unconditionally
sudo mkdir -p /etc/rfxn-defense
sudo touch /etc/rfxn-defense/force-full
sudo /usr/sbin/rfxn-redetect

The auditor reports force-full sentinel active when the sentinel is on. Remove the file and re-run rfxn-redetect to re-engage detection.

Verify

# cf1: AF_ALG socket creation should fail
python3 -c 'import socket; socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0)'
# expect: PermissionError [Errno 1] Operation not permitted

# ssh-keysign-pwn: ptrace_scope should be 2 on hardened host
cat /proc/sys/kernel/yama/ptrace_scope
# expect: 2

# Holistic per-class coverage report
sudo rfxn-local-check
# tail-of-output:
#   Surface area / mitigation matrix:
#     Class                  Sink reachable?  Mitigated?  Active layers
#     cf1 (CVE-2026-31431)   YES              yes         ld_preload_shim, systemd_af_alg, modprobe_blacklist
#     cf2 (xfrm-ESP)         YES              yes         modprobe_blacklist, systemd_restrict_ns
#     Dirty Frag-ESP         YES              yes         modprobe_blacklist, systemd_restrict_ns
#     Dirty Frag-RxRPC       YES              yes         modprobe_blacklist, systemd_af_rxrpc
#     PinTheft (AF_RDS)      YES              yes         rds_modprobe, af_rds_restrict, rfxn_afrds
#     keysign-pwn (ptrace)   YES              yes         ptrace_scope, rfxn_pidfd_getfd

Override paths

systemd drop-ins use the standard layered-override pattern: within a <unit>.service.d/ directory, files merge in lex order and lower numbers lose to higher numbers for =value directives. rfxn-defense ships at 10-, 12-, 15-; operator escape hatches sit at 20- and 25-.

20-override.conf (neutralize a directive). Empty = clears the union for list-valued directives. Survives package upgrade (operator-owned, RPM does not manage it):

sudo install -d /etc/systemd/system/user@.service.d
sudo tee /etc/systemd/system/user@.service.d/20-override.conf >/dev/null <<'EOF'
[Service]
RestrictNamespaces=
RestrictAddressFamilies=
EOF
sudo systemctl daemon-reload

25-additions.conf (add a directive on top of ours). Sorts after 20-:

sudo tee /etc/systemd/system/sshd.service.d/25-additions.conf >/dev/null <<'EOF'
[Service]
NoNewPrivileges=true
EOF
sudo systemctl daemon-reload
sudo systemctl try-reload-or-restart sshd.service

modprobe override: conditional cf2-xfrm.conf and rxrpc.conf are managed by detect.sh (cmp-and-skip). Hand-edit and detect.sh logs a WARN on the next %posttrans/rfxn-redetect and preserves your edits. The always-on cf1.conf is %config(noreplace). Do not chattr +i a managed file: it breaks dnf via EPERM on install -m 0644.

Auditor JSON (v2.0 schema)

{
  "schema_version": "2.0",
  "covers": ["cf1", "cf2", "dirtyfrag-esp", "dirtyfrag-rxrpc", "pintheft", "keysign-pwn"],
  "posture": {
    "verdict": "vulnerable_kernel_userspace_mitigated",
    "bug_classes_covered": ["cf1", "cf2", "dirtyfrag-esp", "pintheft", "keysign-pwn"],
    "bug_classes": {
      "cf1":             { "applicable": true, "mitigated": true,  "layers": {} },
      "pintheft":        { "applicable": true, "mitigated": true,  "layers": { "rds_modprobe": true, "af_rds_restrict": true, "io_uring_disabled": true } },
      "keysign-pwn":     { "applicable": true, "mitigated": true,  "layers": { "ptrace_scope": true, "pidfd_getfd_auditd": true } }
    },
    "auto_detect": { "available": true, "suppressed_modprobe": [], "suppressed_systemd": [] }
  }
}

bug_classes_covered is the SIEM-ergonomic single filter ("is this host hardened?"). bug_classes exposes per-layer breakdown for finer dashboards. verdict and layers from v1.0.x are preserved for backwards compat. Exit codes (unchanged): 0 clean, 2 VULN, 3 VULN-but-mitigated, 4 hardening recommendations only.

Direct downloads

Each release on github.com/rfxn/rfxn-defense/releases ships per-EL binary RPMs, an SRPM, the .repo file, and the public signing key as release assets. v3.0.2 is the current line; older v3.0.0 / v3.0.1 / 2.0.x / 2.1.x RPMs are archived under repo/N/x86_64/archive/ in the dnf repodata so dnf upgrade resolves cleanly from any installed version.

The .repo file (works on EL7/EL8/EL9/EL10):

sudo curl -sSL https://rfxn.github.io/rfxn-defense/rfxn-defense.repo \
  -o /etc/yum.repos.d/rfxn-defense.repo

The public signing key (dnf imports automatically on first install; pre-import for offline verification):

sudo curl -sSL https://rfxn.github.io/rfxn-defense/RPM-GPG-KEY-rfxn \
  | sudo rpm --import /dev/stdin

Per-EL binary RPMs are independently compiled against each distribution's glibc (EL7: 2.17 split libdl; EL8: 2.28 split libdl; EL9/EL10: 2.34+ merged libdl). Do not cross-install across ELs.

EL7 (CentOS 7 / RHEL 7, vault.centos.org build)

Filesha256
rfxn-defense-3.0.2-1.el7.x86_64.rpm 8f77d9f780190cc119a086ccd6412cd8f10c6c20b7aa64b17b4c2c7e8049c948
rfxn-defense-audit-3.0.2-1.el7.noarch.rpm 491eb8a04efde5c5863cc9c4d92f8a5b8d23189ce32f3b0a6f94063ecb98ea0d
rfxn-defense-auditor-3.0.2-1.el7.noarch.rpm e8f534b8779ff2e36a64c246c84f4147aaa4bff07d4f9f09a9bd12ae4d426053
rfxn-defense-autoupdate-3.0.2-1.el7.noarch.rpm a7ea637ee8270a4c2b5e67245c75f6b81ab3fa45c9e01732c74eb2258a1fa255
rfxn-defense-modprobe-3.0.2-1.el7.noarch.rpm 81d3b922d9f7cb36d543f556e5c64e0f68c87d702cf11c4a863fc63b7b23b56c
rfxn-defense-shim-3.0.2-1.el7.x86_64.rpm bb179e2c7654b6ed4e8da4fe88836b911030f4242f5bd9f04633d3d9a1ba24be
rfxn-defense-sysctl-3.0.2-1.el7.noarch.rpm d143dc30a1b57e2b529bc19d0b59a46ec540b8640935a46c67841a2ef2fb6990
rfxn-defense-systemd-3.0.2-1.el7.noarch.rpm 3c2f8bb8a44a5bd3dc462ad2631dbaaa51b14f1f2c54aefd9095ca76590f1fe0
rfxn-defense-3.0.2-1.el7.src.rpm 517c25d7032e76d1bebacb0fb1a0e3f65b6abde0ea2b75d5abf8463cf93909f9

EL8 (RHEL/Alma/Rocky/CentOS Stream 8)

Filesha256
rfxn-defense-3.0.2-1.el8.x86_64.rpm efd42dd8d071421c21dfd307320e0ef2b99bee4a30d7510e22dac57539371542
rfxn-defense-audit-3.0.2-1.el8.noarch.rpm 50b8a9be6ba6ff2a6e8c427d97be91f8253b14829b672fced46e625ea2843524
rfxn-defense-auditor-3.0.2-1.el8.noarch.rpm 150f42b877d7c3b054002100ef399db759531c587f7ad9df4713e2a2c93a76ae
rfxn-defense-autoupdate-3.0.2-1.el8.noarch.rpm cc47306e220390f5565e339173bfd97411bf8e870615c9856456a118c7fbd7cd
rfxn-defense-modprobe-3.0.2-1.el8.noarch.rpm 95e7b001d3b7cfd3529c55bd33b707cac68ece616a457f25b53c10a3a84f6d30
rfxn-defense-shim-3.0.2-1.el8.x86_64.rpm 9715db9bfc8ff4c99183f638c0847b5f6235265e56ab1b459ae8cb95f392e91b
rfxn-defense-sysctl-3.0.2-1.el8.noarch.rpm 15b59442af3093d45351fc917cee812eab64a5ccd196f0c3875c076ee454edee
rfxn-defense-systemd-3.0.2-1.el8.noarch.rpm cf42b0266d8ed40c28b8dea5f1091fdd0128706d465fcf51981a2c6ac8bc7437
rfxn-defense-3.0.2-1.el8.src.rpm 3bf05c48fa78d2cfbe819f557b939e12c79fa1eb8e7ffe45d1180f5593fdc8b1

EL9 (RHEL/Alma/Rocky/CentOS Stream 9)

Filesha256
rfxn-defense-3.0.2-1.el9.x86_64.rpm 379a21e8cc6198e92c39109f26e043b19bdace9254112d2db29202503bf3e5aa
rfxn-defense-audit-3.0.2-1.el9.noarch.rpm 8152b328cbe64fbab4fb701bfb22780e4f9bf29d6c57b186931159df31854c45
rfxn-defense-auditor-3.0.2-1.el9.noarch.rpm 795b0a776b12e066e948d1c1e3949fb7ed8ffd3edc1b37fd117964c746e88d2e
rfxn-defense-autoupdate-3.0.2-1.el9.noarch.rpm 5de34329a105fbe9f1f6347e87dabbbc538dc1260a74cb1fdcb6f378f92bfd40
rfxn-defense-modprobe-3.0.2-1.el9.noarch.rpm 3af3b411af4828937908e77b3948431dba7eeb9bdd95880395f68dc8d7e8d217
rfxn-defense-shim-3.0.2-1.el9.x86_64.rpm 52916845017ccc0c674e05e05c60aae9bcaeb416f713ad28f27223bcf9ac5b36
rfxn-defense-sysctl-3.0.2-1.el9.noarch.rpm dd44ab6e8d737b1a421a12a3b300dcc4abf401ed2d808afd7d40d87752af66c6
rfxn-defense-systemd-3.0.2-1.el9.noarch.rpm bec85dd0897280e43aec1e0e490ccbd21dc5c3b9201b8dd73c5a031dcfbe3b7c
rfxn-defense-3.0.2-1.el9.src.rpm 2e29a3f34d22a92f2cac34b11932d9eafa61370d7004b8eea0ac04c501de937b

EL10 (RHEL 10 / CentOS Stream 10 / AlmaLinux Kitten)

Filesha256
rfxn-defense-3.0.2-1.el10.x86_64.rpm fec9f133b123fbbd1bfaea85736f8620c4890159edb188b0e234877f88f06ac7
rfxn-defense-audit-3.0.2-1.el10.noarch.rpm c5c0db5ef103be35879f33104a3fab0d8b81afdd954fc4ca935809613e461626
rfxn-defense-auditor-3.0.2-1.el10.noarch.rpm 78dbd678b2e209d36e07985483c582e34867b9ac033b4e792dbb6ca4a3f4e7c4
rfxn-defense-autoupdate-3.0.2-1.el10.noarch.rpm 0672dd4317b5bc83c0bacefa513728138a80a2e186bd7f00bbde88ac5aa7876f
rfxn-defense-modprobe-3.0.2-1.el10.noarch.rpm 8b9cd054342f5694118a560eaddb379720f4c72e0bfc312e71ec68d26cf23e96
rfxn-defense-shim-3.0.2-1.el10.x86_64.rpm 320ba68792c474f0f1a0f123836e96c95f01f9fc06dbe7a0ab0cd7d36c73cee7
rfxn-defense-sysctl-3.0.2-1.el10.noarch.rpm a22e6b8b2d946e13d2f9cda5ee985c1d26189c2ae453727802ade37d520caa5f
rfxn-defense-systemd-3.0.2-1.el10.noarch.rpm 6d4b18a6cf540e95bb98f48fb5b8b2d7e3b931df6ac4228806c9de4af52b9459
rfxn-defense-3.0.2-1.el10.src.rpm 9e8f1262f2a07ee5a042d068778d0c3491edd7ffed1e3cf10896557bdab0c08f

Signing

v1.0.1 and later are signed by the Copyfail Project Signing Key (retained as the project's canonical signing identity through the v3.0.0 rfxn-defense rename):

fingerprint: 6001 1CDC EA2F F52D 975A  FDEE 6D30 F32C D5E8 0F80
uid:         Copyfail Project Signing Key <proj@rfxn.com>
key file:    /RPM-GPG-KEY-rfxn
             (legacy alias: /RPM-GPG-KEY-copyfail, identical content)

The rfxn-defense.repo sets both gpgcheck=1 (verifies each RPM) and repo_gpgcheck=1 (verifies repomd.xml via the detached repomd.xml.asc we publish alongside it). dnf imports the public key from gpgkey= on first use.

Verify out-of-band:

curl -sSL https://rfxn.github.io/rfxn-defense/RPM-GPG-KEY-rfxn | gpg --import
gpg --fingerprint proj@rfxn.com
# expect: 6001 1CDC EA2F F52D 975A  FDEE 6D30 F32C D5E8 0F80
rpm --import https://rfxn.github.io/rfxn-defense/RPM-GPG-KEY-rfxn
rpm -K /path/to/rfxn-defense-3.0.2-1.el9.x86_64.rpm
# expect: digests signatures OK

Defense in depth

Each rung defeats the bug by a different mechanism, so an attack that defeats one does not necessarily defeat the next.

RungWhere it failsWhat the next rung covers
Kernel patch (vendor) EL7 EOL; rollout on supported ELs lags disclosure days-to-weeks; reboot may not be available; DF-RxRPC, PinTheft, ssh-keysign-pwn have no upstream patch as of v3.0.0 Userspace cuts close the window without a reboot; rfxn-defense is a kernel-patch-free coverage path
modprobe blacklist No-op when relevant module is builtin (RHEL algif_aead); no effect on already-resident modules Functional for esp4/esp6/xfrm_user/xfrm_algo/rxrpc/rds* on stock RHEL kernels
systemd RestrictAddressFamilies / RestrictNamespaces Reaches only services systemd starts post-restriction. Misses cron-as-root, sshd-pre-restriction, container payloads with own pid 1, interactive shell exploit binary Host-wide userns sysctl catches the interactive-shell case; LD_PRELOAD shim covers every dyn-linked process regardless of init
Host-wide userns / ptrace / io_uring sysctls Auto-suppressed on rootless / Flatpak / firejail / browsers (userns); io_uring workloads; pre-6.6 kernels (io_uring). In-flight processes retain a userns they already grabbed Per-unit RestrictNamespaces still applies on tenant units; auditd logs post-suppression userns prep
LD_PRELOAD shim Static binaries; direct syscall instruction; SUID strip seccomp at unit/runtime level catches direct-syscall path
auditd tripwire rules Detection only, not mitigation. Fails when auditd is not running or rules are unloaded Becomes the residual signal on hosts where modprobe blacklists are auto-suppressed (IPsec / AFS / RDS workloads) and the kernel sink stays reachable

Where the shim itself fails (static binaries, direct syscall, SUID stripping) is attacker engineering territory. The other rungs fail under routine operator reality: vendors haven't shipped yet, the kernel was built with builtin crypto, the threat surface includes a cron job. That asymmetry is the case for deploying every rung.

Changelog

Per-release notes (full detail): github.com/rfxn/rfxn-defense/releases. Per-commit history: github.com/rfxn/rfxn-defense/commits.

VersionDateSummary
v3.0.2 2026-05-24 EL7 silent-failure closure. Empirically validated against a fresh CentOS 7.9.2009 VM (systemd 219, procps-ng 3.3.10, kernel 3.10). Critical: systemd v219 (EL7) silently ignores RestrictNamespaces= (added in v235); the userns drop-in shipped on every prior 3.0.x build was inert at unit-start on EL7. Critical: EL7 procps-ng 3.3.10 mis-parses the sysctl.d(5) -key silent-skip prefix (added in 3.3.12), so every key in 99-rfxn-defense-ptrace.conf and 99-rfxn-defense-userns.conf silently no-op'd - ssh-keysign-pwn (CVE-2026-46333) primary mitigation latent on every EL7 host. Both layers now distro-gated; the ptrace_scope sysctl dropped the - prefix. Critical: %posttrans sysctl loop omitted ptrace.conf entirely - replaced with sysctl --system so the file actually applies at install time on every distro. Auditor: systemd_restrict_namespaces no longer silent- SKIPs on EL7 (now emits explicit "predates v235" reason or FAIL with stale drop-in list); userns_sysctl OK message distinguishes "blocked by rfxn drop-in" from "blocked by kernel/distro default"; ptrace_scope remediation text points at the correct file (was stale from v3.0.0). New packaging/test-el7-live.sh live-host runner with 33 assertions including empirical mitigation probes that isolate each layer.
v3.0.1 2026-05-24 Fixup release validated against live cPanel + admin hosts. Critical: systemd drop-in deny-list syntax was ~A ~B ~C (parse-fail; RestrictNamespaces silently became no and ~AF_KEY / ~AF_RDS denial never applied); fixed to ~A B C. kernel.yama.ptrace_scope=2 split into its own always-applied drop-in (was bundled in userns file and lost with any rootless/Flatpak/firejail/browser suppression). Rootless detector Signal 2 tightened to require a real container/image artifact (overlay-containers/* non-lockfile), ruling out podman-installed-but-unused hosts. Auditor fixes: recognises auditctl -l hex format (a0=0x26) by matching key=rfxn_*; credits the LD_PRELOAD shim under cf1 instead of misreporting n/a; banner updated to 7-class coverage.
v3.0.0 2026-05-23 Project rename copyfail-defenserfxn-defense; reframe as general-purpose responsive defense layer. New -autoupdate subpackage: 4-hourly cron + flock wrapper, lands new mitigations within 4 hours of a release tag. DirtyDecrypt (CVE-2026-31635) cross-stamped onto DF-RxRPC coverage. Double Obsoletes/Provides chain handles v2.x upgrade; state migrates via %pretrans mv -n.
v2.1.1 2026-05-23 io_uring sysctl promoted from opt-in to auto-applied with layered suppression. New 99-rfxn-defense-iouring.conf drop-in (Linux 6.6+ only). Older RPMs moved to repo/N/x86_64/archive/.
v2.1.0 2026-05-22 PinTheft (CVE-2026-43494) Copy Fail extension via RDS + io_uring; ssh-keysign-pwn (CVE-2026-46333) FD-theft class. kernel.yama.ptrace_scope=2 sysctl; rfxn_afrds + rfxn_pidfd_getfd auditd rules. EL7 build target via vault.centos.org.
v2.0.2 2026-05-13 Fragnesia / Dirty Frag-ESP coverage. New -sysctl subpackage (user.max_user_namespaces=0); new -audit subpackage (~AF_KEY closes the PF_KEYv2 SA-config path). CVE cross-stamping for cf2 (CVE-2026-43284) and DF-RxRPC (CVE-2026-43500).
v2.0.1 2026-05-08 Workload auto-detection: IPsec / AFS / rootless-container suppression in %posttrans; per-host state at /var/lib/rfxn-defense/auto-detect.json. File-layout split (3 modprobe files, 3 systemd drop-in layers).
v2.0.0 2026-05-08 Umbrella rename afalg-defensecopyfail-defense; expanded to the Copy Fail bug class. New -modprobe and -systemd subpackages.
v1.0.1 2026-04-29 Initial signed release. afalg-defense-shim (LD_PRELOAD AF_ALG block) and afalg-defense-auditor (read-only host posture auditor). RPMs and repodata GPG-signed.

Reporting issues

Bugs, packaging problems, false positives, missing distros: please file a GitHub issue. Include the auditor's --json output if the report is about detection, and the output of uname -a + cat /etc/os-release for any runtime question.