Changelog
Notable changes to PrivacySafe Security Patches, newest first.
2026-11-04
New
- APT package downloads swapped after verification (CVE-2026-109518, 4 November):
apt-nov2026-check.sh. APT can merge two package downloads when an HTTP redirect gives them the same address and reuses a file through a hard link when it retries, so someone who can alter the HTTP traffic (an attacker on the network path, a malicious mirror or a proxy) can replace a package after APT has verified it, and the replacement is installed as root. It needs both a redirect and a retry:Acquire::Retriesis 3 by default on Debian 12 and Ubuntu 22.04 and later, so older releases are not exposed unless something turned retries on.checkjudges the installed APT against the fixed release of its line (3.3.6, 3.2.1, 3.0.4, 2.8.4, 2.6.2, 2.4.15, 2.2.5 and the older lines of the CVE record, and the Ubuntu builds that fix a line below those), reads the effective retry and redirect settings throughapt-config, and lists the sources that use plain http; it exits1only when the version is vulnerable and both conditions are on.huntcompares cached packages with the SHA-256 in the index and looks for hard-linked files in the package and list caches, and says plainly that no indicator is published.mitigatewrites one file in/etc/apt/apt.conf.dthat setsAcquire::Retriesto 0, confirms the effective value withapt-configand removes the file again if another setting wins;rollbackremoves it. Updating APT is the fix, and the README gives the update command with retries off for the update itself.
Changed
- Release 26.11.04-1.0.0 replaces 26.10.30-1.0.0 and covers 2 to 4 November. A script carries the date of its last change: the new APT script 2026-11-04, the 62 other scripts that are new or changed since 26.10.30 (BTCPay Server, eMudhra on macOS, the IPv4 TCP tool and the module blocker, and the 58 that changed for root and sudo handling, the hunts and locking) 2026-11-03, with a new patch version for the 58.
php2shell-edge-test.shdid not change and keeps the date of its last change. It only sends HTTP requests, so root does not matter to it. - The lock that every script that can change a host takes covers the APT script too, so all 26 of them are covered.
- nginx and CVE-2026-42533: the nginx README now explains the July script engine flaw (a critical heap overflow, fixed in 1.30.4 and 1.31.3), which this tool's version bar already covers, and a regression that a downstream distribution reported on 4 November in the Red Hat family backport of that fix (some requests answered with HTTP 500,
no buffer space in script copy, when asetorrewriteuses avolatilemap variable whose value contains variables).nginx-oct2026-check.sh checkprints one information line, and changes no verdict or exit code, when the running configuration has avolatilemap on a Red Hat family host. The Red Hat advisory index now includes CVE-2026-42533, so the nginx README lists its 10 advisories and the RHEL builds that carry the fix (nginx-1.20.1-28.el9_8.6for RHEL 9.8,nginx-1.26.3-6.el10_2.7for RHEL 10.2, the 1.24 module builds for RHEL 8.10 and 9.8, and the 9.2, 9.4 and 9.6 builds of 2 November). We have not reproduced the regression.
2026-11-03
New
- Red Hat advisories (no new CVE): Red Hat's published list of security advisories for 1 April to 3 November 2026 is matched against the CVEs the collection covers. 37 of the 140 have advisories, 396 in all (41 Critical, 351 Important, 4 Moderate), and 16 tool READMEs now have a Red Hat advisories section with the advisory, the fixed package release and the RHEL stream:
bind,brotli,curl,haproxy,jenkins,linux-kernel,nginx,node,openssl,php,pillow,pki,ruby,storybookandtomcat, withphp/edgepointing at PHP. The kernel section is a table of ten RHEL streams against the six kernel CVEs, and a list of the fixed kernels for CVE-2026-98432.REDHAT-ADVISORIES.mdis the index by tool and by CVE and is a page of the documentation site. The sections are generated bypackaging/rhsa/rhsa.pyfrom Red Hat's list (find,verify,fetch,index,docs,audit); editplacement.jsonor the data, not the marked block.rhsa.py verifyalso checks an installed package against the fixes, within one stream, one version line and one OpenShift release, and says "check by hand" when it cannot judge. The.deband.rpminstall the checker as/opt/psf-security-patches/rhsa/rhsa.pywith the manual pagepsf-rhsa(8), so a Red Hat family host can runverify --rpmafter installing the package;python3is a recommended dependency of both packages, not a required one, so every other tool still installs and runs without it.verify --listchecks against a list downloaded withfetch, andindex --allkeeps every CVE in a list. - Linux kernel IPv4 TCP use-after-free (CVE-2026-98432, 2 November):
linux-kernel-ireq-opt-check.sh. A race in the IPv4 TCP handshake that an unauthenticated peer triggers with a SYN carrying IP options; AWS reports remote code execution shown against an MPTCP listener.checkjudges the running kernel against the fixed release of its branch (5.10.272, 5.15.223, 6.1.190, 6.6.159, 6.12.113, 6.18.56, 7.2.10, 7.3), reads the vendor changelog for kernels that backport, and reports the exposure (MPTCP, listeners,tcp_migrate_req, any filter on IP options).huntlooks in the kernel log for the crash side of the flaw.mitigatecan switch MPTCP off, drop IPv4 TCP packets that carry IP options (nftables or iptables, scoped to TCP) and block module loading, androllbackundoes it. These reduce the exposure and do not fix the flaw: the fix is a patched kernel and a reboot. It knows the project's default targets first, Debian, Ubuntu, Trisquel and derivatives, and the RPM family next: the update command, the vendor page and the cachedaptordnf updateinfoevidence for the system it runs on, the right package on Amazon Linux 2023 (kernel,kernel6.12orkernel6.18),needs-restarting -r, nftables instead of aniptablesfront end that has nou32match, and a note when a fixed kernel is installed but not running. - Linux kernel module blocker (3 November, no CVE of its own):
linux-kernel-module-block.sh, a generic tool that stops any kernel module from loading.listshows a table of 42 modules in three labeled groups (recent exploits this collection has a tool for, older well known flaws, and rarely needed attack surface in the CIS style) with what a block breaks and the state on the host;checkexplains any module by name, including how it autoloads;blockwrites a file of its own inmodprobe.dwith a manifest, by name, by group or by CVE;statussays whether each block is effective;rollbackremoves them. It says when a block cannot work: a built-in module (and names the switch), a module that is loaded now (--force,--unload), a module the initramfs loads first (the rebuild command for the system, run only with--initramfs) and a protected list of modules a machine needs to boot.--list-fileadds your own rows. The other kernel tools keep their own copies of this logic and stay standalone.
Changed
- The three Linux kernel tools (
linux-kernel-lpe-check.sh,linux-kernel-ireq-opt-check.shand the new module blocker) take a lock while they change the host. A secondmitigate,blockorrollbackwaits up toPSF_LOCK_WAITseconds (default 30) for the first and then stops with exit 2, so runs started together can no longer overwrite each other's manifest entries. The module blocker also replaces its manifest through a temporary file. - The 22 other scripts that change a host take the same lock (
drf,drupal,haproxy,joomla,nginx,wp2shell,wordpress-plugins,yootheme,tomcat,rsyslog,vsftpd,emudhra-macos,emudhra-mitigate,collabora-code,btcpayserver,claude-code-vsx,libheif,node,php2shell,php2shell-cpanel,ghostactionandlitellm, the last two forquarantine), so all 25 scripts that can change a host are covered. A change command (not a dry run, help or version) re-runs the script underflock -o, so a service the script starts does not inherit the lock, and a tool whose default command changes the host (php2shell-mitigate.sh,emudhra-mitigate.sh) locks when it is run with no command. - The Claude Code extension, Collabora, eMudhra (macOS), vsftpd and
wp2shellscripts remove their temporary files when they are interrupted, not only when they finish.php2shell-watch.shexpands its log patterns withcompgen -G, so a pattern with spaces or no match is handled as it should be. Theexpatandopenapicheckers lost an argument path that was never used. - The documentation site and its offline copy have a manual page for
psf-rhsa(8), the Red Hat advisory checker that the packages install, next to the 63 for the scripts. - The help and READMEs of the BTCPay Server, eMudhra (macOS) and IPv4 TCP tools now list the environment variables they read (
BTCPAY_BASE_DIRECTORY,BTCPAY_FRAGMENTS_PROFILE,TOR_SERVICES_DIR,PYTHON_BIN,SITECUSTOMIZE,KERNEL_PROTOCOLS_FILE). haproxy-check.sh checktells a Red Hat 3.0 build about RHSA-2026:83844. Red Hat shipped a fix for CVE-2026-110353 inhaproxy-3.0.30-0.1.hum1although HAProxy gives 3.1 as the first affected line, so a version thatcheckcalls outside the range now gets a note when it is a Red Hat build (.humor.elin the version). The verdict and the exit code are unchanged.- The Red Hat row of the Linux kernel table lists the ten fixed streams, and the advisory ids it had are confirmed by Red Hat's own list: RHSA-2026:93414 (RHEL 8.10), 93412 (9.8) and 93413 (10.2).
mptcp_diagis no longer treated as part of the flaw. The flawed code is in IPv4 TCP, andmptcp_diagis the moduless -Mreads, so blocking it hides the MPTCP listeners that checks look for and removes no known exposure. In the module blocker it moved from the exploited group to the hardening group with no CVE and a newkeepflag:--groupand--cveskip it with a message, and it is blocked only when named and with--force. In the IPv4 TCP tool--modules allnow meansmptcp, andmptcp_diagneeds its name and--force.- The IPv4 TCP tool follows what the vendors and a real kernel showed for CVE-2026-98432.
checkreads the MPTCP socket count in/proc/net/protocolsand says whenss -Mlists none while the kernel counts some (themptcp_diagmodule thatss -Mneeds can be missing, as on Ubuntu cloud kernels), and notes that the switch,ssand the count describe one network namespace, since a new namespace starts at 1 whatever the host is set to.mitigate --mptcpsays it acted on this namespace only and that sockets already in use survive.mitigate --ip-optionsadds nothing when a filter of the same kind is in place, such as Red Hat's table in RHSB-2026-016, androllbackleaves it.mitigate --modulessays that blockingmptcp_diagonly hides MPTCP sockets. The update hints name Ubuntu's-proposedpocket and Red Hat's bulletin, and the README lists the vendor states as of 3 November: Red Hat fixed RHEL 8, 9 and 10 on 1 November, AlmaLinux has the same kernels in production since 2 November, Ubuntu has the generic kernel in-proposed. - The IPv4 TCP tool no longer reads "no filter found" while its own filter is active. It piped
nft list rulesetandiptables -Sintogrep -qunderpipefail, which fails when grep stops at its first match while the command is still writing; the output is now captured first. The module blocker'secho | grep -qpipelines became here-strings for the same reason. - The IPv4 TCP tool recognizes a
u32filter in the formiptables -Sprints, and says when an MPTCP listener survivesnet.mptcp.enabled=0. - ShellCheck now runs with nothing hidden: 18 unused variables in 14 scripts are gone, and the blanket
shellcheck disablelines no longer include SC2034, so an unused variable shows up as a warning. All 63 scripts have 0 warnings. haproxy-check.sh mitigate --forceandphp2shell-edge-test.sh --insecureare documented in their READMEs.
2026-11-02
New
- BTCPay Server hot wallet thefts (2 November, no CVE): the project's advice for a server that ran 2.4.1 or earlier is a fresh server and a new wallet, not an update, and this tool is built around that.
checkjudges the version,recovergives the recovery plan for the host in the project's order with a pre-filled report, andpreservesaves logs and records into one redacted archive before the old server goes offline.huntreads logs for the published indicators,hardenreviews ports, fragments, LND routes, the IPv4 options filter and SSH, andtorreports and, on request, enables or disables Tor.--strictmakes any warning exit 1 and--jsonprints the result for monitoring.recoverandhardenalso look for signs on the host: the update history against the project's warning (andhuntreads the update log archives), a legacy unrestricted BTCPay SSH key, custom fragments, local changes or a different origin in thebtcpayserver-dockercheckout, and server administrators without two-factor sign-in.checkflags LND older than 0.21.1, and the plan covers Core Lightning and phoenixd as well as LND. - eMudhra on macOS (no new CVE):
emudhra-macos-mitigate.shfor the part of the eMudhra intermediate CA compromise that Apple has not fixed. The command line tools that ship with macOS and the Xcode Command Line Tools (curl,git,python3,ruby,perl,openssl) read/etc/ssl/cert.pemwithout checking revocation, and it still holds the roots the intermediates chain to, as Apple's support page describes; hosted macOS CI images also keep an old Homebrewca-certificates.checkreports both roots in the system and Homebrew bundles, the Homebrew formula version and thepipsetting, and--onlinetests the disclosure site's hosts with curl.applybacks up the bundle, removes emSign ECC Root CA - G3 (and with--include-aaaAAA Certificate Services, which may break unaffected sites), cuts a block only after checking that its certificate has the root's published SHA-256 fingerprint, that the count drops by exactly the roots removed and that OpenSSL can still read every remaining certificate, and puts the original back if its check fails. A bundle OpenSSL cannot read in full is never reported as clean: one damaged certificate makes OpenSSL read none, socheckexits2andapplyrefuses.rollbackrestores it, and refuses when a macOS update has replaced the file. It never runsbrew, which refuses to run as root. The README has a step for hosted runners.
Changed
- The offline documentation site is committed in
docs/, generated from the READMEs bypackaging/gen-site.py --out docs. The repository can be browsed as it is, and Codeberg or GitHub Pages can serve it from that folder. The packages install the same pages under/usr/share/doc/psf-security-patches/html, andpackaging/build-release.shstops whendocs/is out of date. The manual pages and the info manual are still generated for the packages only. php2shell-watch.shandphp-session-audit.shnow print the date with their version, like every other script. The WordPress plugin checker's help starts with a one-line title, so its manual page reads correctly. The PHP edge guards README names the two PHP2Shell CVEs.- Root and sudo are handled the same way in every tool. A command that changes the machine and is started without root now stops and prints the exact
sudocommand to run, with your own arguments (or says to run it as root when sudo is not installed). A change started from the root account itself, with sudo available, prints a one-line note and carries on: it shows once, only on a terminal, not undersudo, not aftersudo su, not in a container and not on a dry run, andPSF_NO_ROOT_NOTE=1hides it. The Claude Code extension's per-user commands (update,clean,keys) still run as the account that uses the editor.php2shell-watch.shnow names a log it cannot read and exits2when none is readable, andphp-session-audit.shandopenapi-codegen-check.shwarn a non-root account. Every README for a tool with a state-changing command shows thesudocommand, and the README and the how-it-works page explain the rule. - Cleanup: about 2,200 lines of unused code are gone. Helper functions that a script defined and never called (the version comparison helpers,
distro_mentions,have, and the new root helpers where a script has no use for them) were removed from 55 scripts. The duplicate systemd unit underpackaging/is gone (the build usesphp/php2shell-watch.service), as is the unusedprivacysafe_header_600.png. Every code file carries anAssisted-bytrailer, and a script that two models changed carries both lines, the newer last. The trailer of the shell scripts is always the last line.
Fixed
- A hunt run without root no longer looks clean when it could not read the logs.
wordpress-ptandwordpress-wp2shellcounted a log they could not open as zero matches and said no strong lead was found; they now say how many logs could not be read and exit2. The BTCPay Server hunt did the same and also printed a raw shell error; it now exits2for an unreadable log or when no log source could be read at all. Eleven more hunts (Brotli, curl, libheif, nginx, Node.js, Ruby, both Grav checks, nginx-ui, YOOtheme and Zammad) now warn a non-root account that a clean result covers only what that account can see. pulsar-check.shwrote a fixed file name under/tmp, which a local user could turn into a symbolic link while the check ran as root. It now uses a private temporary file, and says when docker cannot be used.
2026-10-30
New
- Every README ends with the same footer (important notice, support, contributing, more from PrivacySafe, license), kept in step by
packaging/readme-footer.py. The documentation site draws a solid, one-color icon for each emoji in the READMEs, andcheck-site.pynow also fails a page with a leftover emoji or a tool page that lacks a part the others have. - The documentation is online at privacysafe.app/docs/security-patches, in the PrivacySafe design with the privacysafe.app header, footer and metrics. It has an Atom feed of the newest advisories (
feed.xml), a sitemap, and sits in a/docssection beside the PrivacySafe app guides, the VPN setup guide, the Social guide and the 3NWeb protocols.gen-site.py --theme privacysafe-appbuilds it. - A documentation site, built from the READMEs: a home page that starts with the newest vulnerabilities, tools grouped by kind of software, a CVE index, a short guide to how the tools work, a glossary of the terms the pages use, the install guide, one page per tool with an at-a-glance box (who is affected, the fix, the severity, whether it is exploited, which CVEs, which commands only read and which change something, the command to run, and related tools), a filter for tools that can protect the machine, one page per manual page, the changelog and the policies, with a search that works offline. The offline copy loads nothing from other sites and has no tracking. It is built from the READMEs when a release is built, and the packages install it under
/usr/share/doc/psf-security-patches/html. - Manual pages and an info manual. Every script now has a page (
man psf-haproxy-check), there is an overview (man psf-security-patches) and the same material is available asinfo psf-security-patches. The deb and rpm install them, and their descriptions are rewritten in plain language and list the newer tools. Each page names the AI assistance recorded in the script's header. - vsftpd: a check for CVE-2026-119568, the FTPS session ticket flaw, and for CVE-2025-14242, a denial of service in Red Hat family packages.
mitigateturns offpasv_promiscuous, can require client certificates and can limit who reaches the FTP ports (see Mitigating it).hardenis optional baseline hardening.rollbackundoes both. - Claude Code extension backdoor: check, hunt, clean-up and a firewall block for the tampered extension that Cursor's marketplace served on 29 October. It works on macOS and GNU/Linux.
claude-code-vsx-oct2026-check.ps1is a read-only check for Windows (PowerShell 5.1 or 7). It readsC:\ProgramData\ssh\administrators_authorized_keysas well, which Cursor's ownremediate-windows.ps1does not clean.cleancuts out only the attacker's text when the key shares a line with a real key, so a real key on that line is kept, and it boots the launchd job out of both theguiand theuserdomain.updateinstalls the vendor's fixed build after asking. Enter means yes.keyslists your private keys: type, fingerprint, whether a passphrase protects them, and whichHostentries in~/.ssh/configuse them.cleansaves a record of~/.sshbefore it changes anything.--copy-keysand--drop-agent-keysare optional.
- Protection with rollback for tools that could only check before: HAProxy, rsyslog, YOOtheme, Tomcat, the Linux kernel local root flaws, Joomla, Django REST framework, Drupal core, WordPress core (wp2shell) and nginx. Each one copies a file before it edits it, checks the result with the service's own checker, puts the original back if the check fails, supports
--dry-run, and reloads or restarts nothing unless you ask. - WordPress plugins:
mitigatedeactivates OttoKit, SureCart, LatePoint, Amelia, Profile Builder or Bricksforge when it is below its fixed version. WP-CLI and drush now run as the site's owner, never as root.
Changed
- The offline documentation site now looks like privacysafe.app. It has the same header, ecosystem card and footer, the same warm dark colors and orange accents, and the same pill buttons, with the logos and icons bundled so it still loads nothing from other sites. It replaces the earlier blue theme. The menu's search box now stays pinned while the menu scrolls, and text meant only for screen readers is no longer visible.
- The manual pages were checked with man-db, groff, mandoc and GNU info and tightened. Hyphenation is off, so a command or a setting name is no longer split across two lines. The page date is in ISO form, consecutive CVE headline lines stay on lines of their own, and the page for
php2shell-mitigatesays it runs as root. The page for the PHP2Shell edge tester had "Usage:" as its description.packaging/check-manuals.shruns these checks, and the release build runs it. The.deband.rpmno longer carry the repository's.gitignoreor an empty.nojekyllfile, and the.rpmnow provides the old package name. - The manual pages, the info manual and the offline documentation site are no longer kept in the repository. The READMEs are the documentation here, and privacysafe.app/docs/security-patches is built from them.
packaging/build-release.shgenerates the manual pages and the offline site from the scripts and the READMEs, checks them, and puts them into the.deband.rpm. - The packages are now named
psf-security-patches(they werepsf-security-packages), to match the tools' folder and manual pages. The new.deband.rpmreplace the old package when you install them, so upgrading needs no uninstall. - Defaults are decided for you. nginx
mitigatewith no option applies session tickets off and AIO off. Tomcatmitigatewith no option applies the HTTP/2 measure. The measures that can break software (nginx request buffering, the Tomcat AJP change, user namespaces, plugin deactivation) stay opt-in. - Every README now uses the same section names, and the wording was rewritten for people. The newest vulnerabilities are at the top of the main README.
- Release 26.10.30-1.0.0 replaces 26.10.28-1.0.0. Every script carries the date 2026-10-30.
Fixed
- OpenSSL check:
OPENSSL_NO_PACKAGE=1now ignores the host's package changelog, as documented. Before, a patched system library could make an unrelated local build look fixed.
2026-10-28
Added
- GitLab security releases: a read-only checker for seven High flaws from the 12 and 21 October 2026 releases: CVE-2026-92883 (cross-site scripting), CVE-2026-16301 and CVE-2026-81839 (pipeline authorization; the second is Enterprise Edition only), CVE-2026-14814 (raw-file cache poisoning), CVE-2026-96893 (a Duo Agent Platform prompt injection, Enterprise Edition only), CVE-2026-15723 (LDAP account takeover when SAML and LDAP auto-linking are both on) and CVE-2026-112212 (OAuth/OIDC discovery cache poisoning). Each flaw is judged on its own ranges. 19.2.9 and the other backports of the 21 October release carry only the regular-expression fix, so only 19.5.1, 19.4.3 and 19.3.6 are a full fix. Reads Omnibus, source and container image versions and the edition.
- baserCMS 5: a read-only checker for CVE-2026-114621 (admin and admin API SQL injection, CVSS 8.8), CVE-2026-114622 (path traversal) and CVE-2026-114624 (deserialization leading to command execution), published 23 October 2026. Fixed in 5.3.2 and 5.4.2, with 5.0 to 5.2 moving to a fixed release. Reads
plugins/baser-core/VERSION.txt, judges each flaw on its own range, and reads the two things the CVE-2026-114621 fix adds so a failed or partial update is named. - Jenkins plugin advisory: a read-only checker for the 16 September 2026 advisory, 20 CVEs (CVE-2026-92122 to CVE-2026-92141) in 13 plugins, including eight High sandbox bypasses in Script Security. Reads each plugin's manifest from its directory or its
.jpior.hpifile and compares versions as numbers. - OpenSSL DTLS heap disclosure: a read-only checker for CVE-2026-84782 (High, 8.2: DTLS retransmits handshake messages from a stale buffer offset). Judges distribution packages by their changelog and, for Ubuntu, the fixed package versions. Judges local builds and bundled copies by upstream version. Reports DTLS-capable daemons and processes still holding a replaced OpenSSL.
- Joomla core: a read-only checker for the 29 September 2026 release (5.4.9 and 6.1.4, 16 core fixes), including CVE-2026-90915 (arbitrary directory deletion) and CVE-2026-92222 (SSRF), both rated High. Reads the version constants and the cache-purge fix in the source.
- Zammad: a read-only checker and hunt for CVE-2026-102489 (session hijack leading to code execution as the zammad user; 6.3.0 to 6.5.4 exploitable) and CVE-2026-102490 (local privilege escalation to root, disputed by the vendor). Both are in CISA KEV (2 October 2026). Reports the remote chain from the version and makes no claim that CVE-2026-102490 is fixed.
- Linux kernel ebtables SNAT: a read-only checker for CVE-2026-53266 (CVSS 8.8, CISA KEV 18 September 2026). Judges the kernel by its origin: stable-series kernels by upstream version, Debian through
uname -v, and Ubuntu, RHEL, SUSE and Amazon kernels by whether the vendor changelog names the CVE, so a distribution kernel is not mislabelled from its release string. Reports ebtables SNAT rules, theebt_snatmodule and user namespace settings as information. - Linux kernel local root quartet: a read-only checker for DirtyAH6 (CVE-2026-80844), TUNderflow (CVE-2026-81000), PPPoEject (CVE-2026-68121) and DiagSpill (CVE-2026-74469), four local privilege escalations disclosed on 18 September 2026 with public exploits. Each flaw has its own fixed release per kernel branch, so the first stable releases with all four fixes (5.10.270, 5.15.221, 6.1.188, 6.6.157, 6.12.109, 6.18.50, 7.2.4) are not a single rule. Judges the kernel by its origin, reports each flaw separately, and shows whether the needed module and unprivileged user namespaces are present.
- WordPress page-template path traversal: a read-only checker and hunt for CVE-2026-87902 (CVSS 9.2, CISA KEV 25 September 2026; WordPress 4.7.0 to 7.1.1). Reads the two fixes in
wp-includes/template.phpindependently, so a distribution backport is recognized and a partial patch is named. Falls back to the per-branch version table when the file cannot be read. - Magento, Adobe Commerce and Mage-OS: a read-only checker for CVE-2026-103849 (BlockStrap, CVSS 10.0: an unauthenticated email-template engine flaw; Adobe's fix is APSB26-153 of 13 October 2026, Mage-OS 3.6.0). Gives a firm answer for Mage-OS and for dated release strings, and tells you which patch to confirm for other Magento and Adobe Commerce versions, because isolated patches do not change the version string.
- nginx-ui restricted-directive bypass: a read-only checker and hunt for CVE-2026-84316, CVE-2026-84317, CVE-2026-84318 and CVE-2026-84319 (CVSS 8.3 to 8.8, 12 October 2026): ways around nginx-ui's restricted-directive check for a logged-in user, which run code where nginx loads njs, Perl or Lua. Fixed in 2.4.1. The binary has no version flag, so the script reads a supplied or packaged version and a string the 2.4.1 validator adds to the binary, and reports when they disagree.
- wp2shell, WordPress core RCE: a read-only checker and hunt for CVE-2026-63030 (REST batch route confusion) and CVE-2026-60137 (
WP_Queryauthor__not_inSQL injection), which chain into unauthenticated remote code execution on WordPress 6.9.x and 7.0.x. 6.8.0 to 6.8.5 carries the SQL injection only. Fixed in 6.8.6, 6.9.5 and 7.0.2. Disclosed 17 July 2026, exploited in the wild from 20 July, and in CISA's Known Exploited Vulnerabilities catalog since 21 July. The check judges each flaw from the fix's signature in the core source, so a distribution backport under an older version number is recognized, and it looks for a web server block on both URL forms of the batch route. The hunt reads web server logs,wp-content/uploadsandmu-plugins. - Incus: a read-only checker for CVE-2026-115375 (instance backup path traversal) and CVE-2026-115377 (symlink in a migration stream), both CVSS 4.0 9.4, and CVE-2026-115372 (restricted project
mkfsargument injection). Fixed in Incus 6.0.7, 7.0.2 and 7.5.0. All three let a confined client act as root on the host, so exposure is judged from restricted projects, the unprivilegedincusgroup, trusted certificates and configured remotes. - LiteLLM proxy admin escalation: a read-only checker for CVE-2026-114612 (CVSS 9.9: an
internal_usercan becomeproxy_adminthrough reuse of the salt key). Fixes are per release line (1.100.4, 1.101.3, 1.102.2, 1.103.1, 1.104.0-rc.2). It tells the proxy from SDK-only use and points to the existing tool when it meets the malicious 1.107.0. The existing supply-chain section of the README is unchanged. - Apache Pulsar and Pulsar Manager: a read-only checker for CVE-2026-105869 (critical: with the MultiRoles authorization provider and a non-empty
anonymousUserRole, a forged token can claim any role over HTTP or WebSocket), CVE-2026-105942 (a proxy's credentials used to authorize the original user; needsproxyRoles) and CVE-2026-105944 (Pulsar Manager, CVSS 10, retired: every installation is a finding). Brokers are judged by version and by their configuration. The other twelve advisories in the 21 October announcement are fixed by the same upgrade and are not counted separately. - Amazon SageMaker Python SDK: a read-only checker for CVE-2026-112408 (
default_bucket()uses a predictable S3 bucket name without checking ownership; fixed in 2.257.3 and 3.10.0). It makes no AWS calls. - Sentry for Next.js: a read-only checker for CVE-2026-114139 (the
tunnelRouteoption makes webpack builds skip middleware for every path under the tunnel path, CVSS 9.1; fixed in 9.47.2, 10.75.2 and 11.0.0-rc.1). Exploitation needs four conditions at once, so it judgestunnelRoute, the bundler, colliding routes and says that middleware being the only authorization control must be reviewed by hand. It was run on a real npm-generated lock, and every fixed version and prerelease tag was checked against the real registry. - Jupyter Server and nbconvert: a read-only checker for CVE-2026-114135 (the gateway kernel handler skips the Authorizer's execute check; fixed in jupyter_server 2.6.0) and CVE-2026-114140 (path traversal file write when converting a malicious notebook; fixed in nbconvert 7.17.2). Jupyter Server is judged by configuration, because the bypass needs both a gateway and a restrictive authorizer.
- Storybook: a read-only checker for CVE-2026-114126 (the dev server exposes its WebSocket token to the local network, letting a LAN host write code into story files; fixed in 8.6.19, 9.1.21, 10.6.2 and 11.0.0-alpha.6). Affected versions listen on all interfaces by default, so it checks for a running dev server on a non-loopback address.
- Apache Traffic Server: a read-only checker for CVE-2026-111813 (the experimental
magickplugin passes client query strings to ImageMagickconvert, CVSS 10) and CVE-2026-111811 (thetsmemcacheplugin exposes the shared cache without authentication), fixed in 9.2.16, 10.1.5 and 10.2.1. Both flaws only matter when the plugin is loaded, so it readsplugin.configand the remap files rather than looking for files (the onlymagick.soon a typical host is an ImageMagick coder). It was run on a real Traffic Server 9.2.3. - Grav Login plugin: a read-only checker and hunt for CVE-2026-114658 (a page author can create a super user account through an invitation form; affects 3.6.0 through 3.9.12, fixed in 3.9.13). The hunt looks for super-granting invitation frontmatter, pending super invitations and recently changed super accounts, and never prints the invitation tokens or password hashes.
- Grav core allowlist bypass: a read-only checker and hunt for CVE-2026-116019 (CVSS 8.8: a page editor can run arbitrary public static methods through Flex form overrides; Grav 2.0.15 to 2.2.12, fixed in 2.2.13). Reads
GRAV_VERSIONand the two things the fix adds toBlueprint.php, so a backport is recognized and a partial update is named. - Gitea: a read-only checker for CVE-2026-109553 (SSH certificate principals matched against every stored public key; affects up to 28.1.0, fixed in 28.2.0). It only treats an instance as exposed when it trusts a user certificate authority, as the advisory says, and never prints the CA key.
- YOOtheme Pro: a read-only checker and hunt for CVE-2026-102785 (CVSS 10.0 unauthenticated remote code execution through the image handler; affects YOOtheme Pro 5.0.0 through 5.0.52, fixed in 5.0.53). It covers the WordPress theme and the Joomla template, hunts for PHP in media and cache directories, PHP inside image files and web log requests that run them, and documents nginx and Apache rules.
- ISC BIND 9: a read-only checker for CVE-2026-94300 (GSS-TSIG replay memory corruption; fixed in 9.20.30 and 9.21.27; the end-of-life 9.18 branch moves to 9.20). It follows the
includechain ofnamed.conf, reports GSS-TSIG settings as a hint rather than proof of safety, and was run against real BIND 9.18.39. - rsyslog dynaFile: a read-only configuration audit for CVE-2026-92709 (dynaFile path traversal; no release is listed as fully patched). It finds untrusted properties used in dynaFile paths without secure-path handling, and documents the fix syntax, validated with the real
rsyslogd -N1, including that strict mode is a configuration error on older versions. - Drupal core Field UI: a read-only checker for CVE-2026-108097 (SA-CORE-2026-014, critical remote code execution reachable through contributed modules or custom code; fixed in 10.6.19, 11.3.19, 11.4.10 and 12.0.0-beta2). End-of-life branches are affected and unpatchable, so they always fail. It reads exported configuration for Field UI, Drupal's published workaround, and checks the contributed Entity List module against its own fixed version on every site, whatever the core version (CVE-2026-108099, fixed in 3.0.10; updating core does not fix it).
- Apache CouchDB: a read-only checker for CVE-2026-86471 (a server admin can run shell commands as the CouchDB user; fixed in 3.5.3). It reads the release files, the package and optional live servers, reports the bind address, and never prints a value from the
[admins]section. - Django REST framework: a read-only checker for CVE-2026-114138 (Accept header CPU exhaustion) and CVE-2026-114137 (
TokenProxy.delete()silently revokes nothing), both fixed in 3.18.2. It reads installed metadata and lock files, looks forauthtokenandTokenProxyin project source, notes the neighboring Django version, and documents a token cleanup and an nginx rule. - Craft CMS: a read-only checker for CVE-2026-112777 (Twig
create()blocklist bypass leading to code execution for users with template-execution rights; fixed in 4.18.8 and 5.11.0), with a report ofallowAdminChangesand the Twig sandbox setting. - libexpat billion laughs: a read-only checker for CVE-2026-115506 (entity amplification detected too late; affects libexpat through 2.9.0, fix merged upstream and planned for 2.9.1, not yet released). It reads system libraries,
pyexpatin each interpreter and running processes, flags processes running a replaced library, anddeepscans for embedded copies. - HAProxy HTTP/2 PING: a read-only checker for CVE-2026-110353 (a truncated PING frame pins a worker thread; fixed in 3.4.7, 3.3.17 and 3.2.26). It follows the vendor's release notes, which disagree with the CVE text about the affected range, and audits whether HTTP/2 is reachable, including the implicit clear-text upgrade.
- WordPress XSS2Shell: a version check, parser-differential XSS reflection probe and defensive audit for CVE-2026-64638, plus a
huntcommand that searches web server logs and plugin directories for signs of the five-stage XSS-to-RCE chain. The probe is non-destructive: it generates one failed-authentication entry in the auth log. - WordPress plugins October 2026: a version check for LiteSpeed Cache (CVE-2026-113500, fixed in 7.9.2), Rank Math PRO (CVE-2026-111862, malware in some copies of 3.0.123) OttoKit (CVE-2026-110372, unauthenticated privilege escalation, fixed in 1.1.41) SureCart (CVE-2026-112241, authentication bypass by spoofing, fixed in 4.9.6), LatePoint (CVE-2026-110653, OTP authentication bypass, fixed in 5.7.5) Amelia (CVE-2026-112327, SQL injection, fixed in 2.4.12) and Profile Builder (CVE-2026-112242, privilege escalation, fixed in 4.0.5), and a
huntfor the published indicators of the Rank Math compromise and for signs of OttoKit abuse (new administrator accounts, requests to its REST routes). The hunt reads the database with themysqlclient andwp-config.phpcredentials rather thanwp-cli, becausewp-cliwould run the site's PHP. Adds Bricksforge (CVE-2026-85097, CVSS 10.0, exploited since 7 October 2026: an unauthenticated upload that runs PHP; fixed in 3.1.8.10 and 4.0.1): found by its plugin name, with a hunt forlogin_admin_*.phpand for PHP in the uploads directories. A pre-release of a fixed release now counts as below it. - Apache Tomcat October 2026: a read-only checker for CVE-2026-103119 (AJP response mix-up, 11.0.x) and CVE-2026-101356 (HTTP/2 request and response mix-up, 9.0, 10.1 and 11.0). It reads the exact version from
lib/catalina.jarand readsserver.xmlto see whether AJP and HTTP/2 are switched on. - Laravel TokenGuard: a read-only checker for CVE-2026-114509 (authentication bypass in the token guard on MySQL and MariaDB; fixed in 12.68.0 and 13.29.0), with a protective middleware printed on request.
- Pillow 13.0.0: a read-only checker for CVE-2026-96639 (stale image storage reused after mode transitions) and CVE-2026-112900 (EPS filename argument injection into Ghostscript). It reads installed metadata and lock files and reports whether Ghostscript is present.
- Drupal Webform: a read-only checker for CVE-2026-96355 (template code evaluated from submitted data, SA-CONTRIB-2026-175; fixed in 6.2.12 and 6.3.1), with a configuration scan for custom multiple-value formats.
- Roundcube Webmail October 2026: a read-only checker for the 1.6.20 and 1.7.5 security release (CVE-2026-114716, one of four mail header injection fixes among 20), and a hunt for CRLF probing of the
_uidand_flagparameters in web logs. - Next.js Server Actions: a read-only checker for CVE-2026-94482 (denial of service in App Router apps with Server Actions; fixed in 15.5.28 and 16.4.1), with an nginx rate limit on
Next-Actionrequests. - openapi-typescript-codegen: a read-only checker for CVE-2026-108551, a code injection in the OpenAPI client generator (0.31.0 and earlier, which is every release).
checkfinds the package inpackage.jsonand the npm, yarn and pnpm lockfiles, in installed copies, and in the CI jobs and scripts that run it, and marks a job that fetches its specification from a URL.scanreads generated code and reports any spec-derived value that is not exactly one well-formed single-quoted literal. It never imports or runs anything. - Apache
.htaccessedge guard: the multipart and cookie guards for hosts without server configuration access. It ships as a dry run, becauseLogMessageis refused in.htaccess. The dry run adds anX-PHP2Shell-Guardheader to what it would refuse. Needs Apache 2.4 withFileInfoandAuthConfigoverrides. - Edge guard tester:
php2shell-edge-test.shsends benign requests and checks that a guard behaves as described (enforcing, dry run or log-only), including theContent-Typevariants PHP parses and look-alikes of an allowlisted path. Needs only bash and curl. - Release packages: a source tarball, a
.deband an.rpm, all namedpsf-security-packagesand versioned by release date (YY.MM.DD-X.Y.Z, first release26.10.28-1.0.0). They install the tools to/opt/psf-security-patchesand ship thephp2shell-watchsystemd unit, pointed at that path and not enabled. Builds are reproducible, and the package metadata carries the CC0-1.0 license and the NOTICE.
Fixed
- PHP session audit: a risky session serializer (
php_binaryorphp_serialize) on its own, with upload progress off and no runtime switch in the code, exited0and printed "No precondition found", although its usage defines exit2as a partial match and the same run had already reported condition 1. It now exits2and says it is a partial match. - libheif checker: the
policycheck judged a coder blocked when a policy file was written on one line, because one element'srights="none"could vouch for another element's pattern (adelegateorpathpolicy made HEIC look blocked). Each<policy>element is now tested on its own.harden,unharden,mw-hardenandmw-unhardenput each backup in a directory named only by the second, so two runs in one second overwrote the original backup with an already-edited file. Every backup now has its own private directory (mode0700, which also keeps aLocalSettings.phpcopy, with its database credentials, from being world-readable).huntreported clean when it could read no journal or log; it now exits2. - Collabora CODE mitigator: any option it did not recognize was silently ignored, so a mistyped or invented flag such as
restore --dry-runran a real restore. Only--forceis now accepted and anything else exits2.huntreported clean (exit0, with an "ok" line) when there was no app folder and no readable log. It now exits2and says nothing was searched. - Ruby checker:
scanreported a clean result (exit0) when none of its scan paths existed, andhuntdid the same when it could read no journal or log, so a search with no data looked like a clean one. Both now exit2and say nothing was read. A Discourse version such as3.4.0.beta1was displayed as3.4.0.. It is now shown in full. - Sentry for Next.js, Storybook and Laravel: a pre-release of a fixed release (
10.75.2-rc.1,8.6.19-rc.1,12.68.0-RC1) was judged fixed, because the status functions compared only the numeric part (and Laravel'snorm_verdropped the suffix). A pre-release comes before the release it leads up to, so it now reads as not fixed. A pre-release above the fixed number, and the fixed release itself, are judged as before. - Known limit, stated in the release notes: the checkers that normalize with the shared
norm_verhelper compare only the numeric part of a version, so a pre-release of exactly the fixed number can read as fixed in those that were not individually checked. - PHP2Shell on cPanel: a release candidate, beta or dev build of a fixed release (
8.4.27RC1,8.4.27beta2,8.4.27-dev) was judged patched, because the version comparison sorts those after the final release although they come before it, socheckexited 0 andcleanupwould reduce the drop-in on a build that is not fixed. Such a build is now judged by its numeric part and reads as patched only above the fixed number. - eMudhra mitigation: a certificate file moved out of
/usr/local/share/ca-certificatesor/etc/ssl/certswas kept under its bare file name, so two different files with the same name from different directories overwrote each other in the backup andrestorewould then have put the wrong certificate back. Each is now kept under a numbered name. Backup directories were named only by the second, so two runs in one second shared one and the second overwrote the first run's copy ofca-certificates.conf. The process id is now part of the name. - PHP2Shell mitigation:
removebacked up the AppArmor profile, your local override and the disable link into one directory under the same file name, so each copy overwrote the previous one and the site-specific rules in the local override were lost (with a disable link present, only the link survived). Each now has its own name. Backup directories were named only by the second, so two runs in the same second overwrote the first backup. The process id is now part of the name. The message printed when the generated AppArmor profile fails to parse said "nothing installed" although the ini drop-in from step 1 had already been written. It now says what was and was not changed. The undocumentedPHP_VERenvironment variable, which limits a run to one version like--php, is documented. - Eight more checkers read running containers. LiteLLM, SageMaker, Apache Traffic Server, YOOtheme, the WordPress plugins checker, nginx-ui, Apache Pulsar and the OpenAPI codegen checker now look inside running docker and podman containers (
SCAN_CONTAINERS=1, the default), by the same read-only probe and per-container isolated run, and each sends only what it reads: LiteLLM sends a one-line marker for each proxy config and only the matched image tags, so API and master keys stay in the container. Traffic Server blanks every line that does not loadmagick.soortsmemcache.so. Pulsar sends only the four authorization settings it judges. The WordPress plugins checker sends only thePlugin NameandVersionheader lines and the file's modification time (Rank Math PRO's arrival-time test then uses the modification time alone and says so). Nginx-ui runs its two binary-signature tests inside the container instead of copying a 40 MB binary. LiteLLM and Pulsar also search/appand/pulsar, where the official images keep their configuration. The shared staging helper no longer depends on ahave()function the script may not define (the OpenAPI checker has none, which made staging silently skip). - Thirteen more checkers read running containers. Next.js, Sentry for Next.js, Storybook, Laravel, Django REST framework, Jupyter, Pillow, BIND, HAProxy, Tomcat, CouchDB, libexpat and Gitea now look inside running docker and podman containers (
SCAN_CONTAINERS=1, the default). The JavaScript, PHP and Python checkers copy only the project files they need through a read-only probe (route directory names only for Sentry;.envis never copied, only itsDB_CONNECTIONline). The daemon checkers capture the daemon's version output and its configuration, with secrets (TSIG and RNDC keys, HAProxy passwords, keystore passwords, CouchDB admin entries, the Gitea CA key and every otherapp.inivalue) redacted inside the container before anything is copied, then run once per container in isolation. Pillow judges a container's copy by that container's own Ghostscript. A staged symlink is never kept (docker cpcopies the link itself, which the host-side check would then have followed). The same protection was added to the ten checkers that read containers earlier. The statements in the Tomcat and Gitea READMEs and--helpthat containers cannot be inspected were corrected. - Web-application checkers now read installs inside running containers. The WordPress path traversal, Joomla, Magento and Mage-OS, baserCMS, Grav core and Login, Roundcube, Craft CMS and Drupal core and Webform checks find installs in running docker and podman containers by their marker file, copy only the files they read into a private temporary directory, and judge them like host installs (
SCAN_CONTAINERS=1, the default). They run it once in the main shell and pass the copies on as ordinary directory arguments. Nothing is run in a container beyondfindand a file copy, and.envandwp-config.phpare never copied. - Running containers are now checked by OpenSSL, Jenkins and Zammad. With
SCAN_CONTAINERS=1(the default) the OpenSSL checker asks each running docker or podman container for its own distribution, package andopenssl versionand judges it by the container's rules (Ubuntu's fixed builds per release, the container's changelog, the upstream version where there is no package database). The Jenkins checker reads the advisory plugins' manifests inside containers. The Zammad checker readsVERSIONunder/opt/zammadand/usr/share/zammad, and never judges a container by the host's package version. They join GitLab, nginx-ui, Pulsar, LiteLLM, curl, nginx, Plex and others that already looked inside containers. - Every README now has a "know before you run it" section. The 33 that lacked one (the newer checkers and a middle group of older ones) now list what the tool is and is not, drawn from each script's own stated scope: the fixed versions, what a version number cannot show, what it reads, which flaws are conditional, and where a hunt exists or does not.
- LiteLLM checker: a scan path that exists but cannot be read left
checkreporting clean (exit0) although its usage promises exit2for something it could not read. It now exits2when nothing else is found. - GhostAction checker:
checkreported itself as a C2 indicator (exit1, "credentials may be stolen") when run from the directory it was downloaded to, because its own text names the domains. It now leaves its own file out. It also reported a clean result (exit0) when every scan path was missing, and its usage promises exit2for something it could not read: that is now implemented.huntwrotecrontab -loutput to a fixed file in/tmp. It now uses a private temporary file. - Plex checker:
huntreported any copy of its own script found under a scanned scratch directory. It now leaves out the running file. NewHUNT_ROOTSsetting for the directorieshuntsearches. - Node.js mitigator:
statusexited1when the installed guard matched the shipped one, which is the healthy case; it now exits0. - Runtimes found only on
PATHwere never found. The curl, nginx, Ruby and Brotli (Node.js scan) checks and the Node.js mitigator searchedPATHwithcommand -v -a, which is not a valid option in bash and failed silently, so only a fixed list of locations was searched. A Node.js, Ruby, nginx or curl installed elsewhere onPATHwas reported as not present. They now usetype -a -P. - Pre-releases and non-version text were judged fixed. In the Brotli checker, a
nodethat printedv24.22.1-pre,-rc.0or-nightly…was reported fixed at the fix version, and one that printed text (an error from a broken version-manager shim) was reported fixed because non-numeric text sorts after every number. The same function judges Bun, Envoy, Istio, cdxgen and the Ruby and PHP Brotli extensions. A-devsuffix was also damaged before it was judged (everyvwas removed from the output). All of these are now reported as unknown. The Node.js mitigator dropped a pre-release suffix the same way and now keeps it. A runtime it cannot judge on disk makescheckexit2, as its README says. - One unreadable binary could end a whole check. Under
set -e, an unreadablecurl(or anodethat printed no version) made the curl check and the Node.js mitigator stop silently after a few lines with exit1, so later findings, such as a vulnerable libcurl, were never reported and the status looked like "vulnerable". The PKI mitigator did the same, with exit3, whenopensslfailed during its certificate self-test. All three now report the problem and finish. - curl checker: a development build (
8.20.2-DEV) at a fix version was reported as fixed. It is now reported as unknown, because it is a build made before the release. - WordPress XSS2Shell checker:
checkandauditnow stop with exit2when no URL is given, instead of relying oncurlfailing.auditreported a clean result (exit0) for a site that did not answer. An unreachable target is now an error (exit2), as its usage text always said. Its HTTP response bodies, which can contain an exposedwp-config.php, were written to fixed, world-readable files in/tmpand left behind when a run was interrupted. It now uses one privatemktempfile that is removed on every exit path. - Exit codes. Ten check and mitigate tools (Brotli, curl, GhostAction, libheif, LiteLLM, nginx, Plex, Ruby, the Collabora CODE mitigator and the Node.js mitigator) exited
1on a fatal error such as a mistyped command or an unknown option, although their READMEs document2for errors and1means findings. They now exit2. The PKI and PHP mitigators keep their own documented exit codes. - Environment variables that several tools read but did not list (the Brotli per-product fixed versions,
BACKUP_ROOT,SCAN_CONTAINERS,GUARD_SRC,SCAN_DEPTH,CODECS_SINCE_DAYS) are now listed in each tool's--help. Two advisory links in the WordPress README pointed at a page GitHub does not serve. They now use the repository advisory address. An unused helper was removed from the Node.js mitigator. - Pipelines that could miss a match. Under
set -o pipefail,producer | grep -q PATTERNcan report "not found" whengrep -qexits at its first match and the producer dies of SIGPIPE. It needs a producer that writes more than a pipe buffer (about 4 KB) after the match. Twelve scripts used the shape (bind, brotli, curl, drupal, heif, nginx, node, both PHP2Shell tools, pki, and both WordPress checkers), several of them against large sources:journalctlin the Node guard-liveness check,rpm -q --changelogin the cPanel PHP tool,openssl s_clientin the PKI tool, and HTTP response bodies in the WordPress probes. Each now reads all of its input and discards the output. What the scripts report is otherwise unchanged. - Inputs that could pass as clean. In the checkers for Zammad, OpenSSL, the Linux kernel, Jenkins, GitLab, Magento and Mage-OS, an input the script could not trust to be a release no longer ends in a clean result. A pre-release build (
7.2.0-pre,3.6.5-dev,3.6.0-rc2,7.0.13-rc1,19.4.2-pre) at or above a fix boundary is a warning, not the fixed release. An unparsable package version oropenssloutput, and a Jenkins plugin whose manifest has noPlugin-Version, are reported as unreadable (exit1) and are never skipped. A pre-release below a fix boundary is still judged exposed. - nginx-ui checker: checks the official
uozi/nginx-uicontainer image by tag, and judges a version supplied inNGINX_UI_VERSIONeven when no binary is found on the host. Both were previously ignored, which let a containerized or remote instance report as clean. Alatesttag is a warning that says the version cannot be read from outside the image. - Node.js tool:
huntexited1on a host with nothing to find, although1means "findings". ARETURNtrap that referenced a function-local variable fired again after the variable went out of scope, andset -uaborted the script. A hunt with nothing to report now exits0.
Changed
- PHP2Shell Apache edge guard (
apache-php2shell-guard.confv3): log-only mode now logs a POST that Apache resolves through a directory index, such as a POST to/. ALogMessageinside an<If>section was not written for those requests, so log-only reported nothing for a request that enforcing then refused, on the path the confirmed chain used. The log line now usesLogMessage's ownexpr=condition. Found by the new tester and verified on Apache 2.4.58; enforcement was not affected. - PHP2Shell edge guards: records which
Content-Typevalues PHP parses as multipart (as parsed by PHP 8.3.6) against what both guards match. Every value PHP parses starts withmultipart/form-data, so the guards need no change. - PHP2Shell hunt: notes that a double-free crash on 8.4.27 or 8.5.12 may be php-src issue 24488, a SimpleXML garbage-collector bug, and is not by itself evidence of exploitation.
- Statement of scope: 57 scripts addressing 139 CVEs across 67 software projects and 10 programming languages, plus 4 other global security incidents.
- Brotli checker: 1.3.0 reports the Ruby
brotligem (fixed 0.9.1) and the PHPbrotliextension (fixed 0.21.1), lists running processes that havelibbrotlidecloaded and flags any still running a library replaced on disk (restart needed), and notes dotnet, duckdb and clickhouse when found onPATH, because they bundle an unfixed copy. That last list is informational and does not change the exit code. - Brotli documentation: corrects the description of the bug (an unchecked return value in
DecodeBlockTypeAndLength()that lets a crafted stream write past an eight-byte buffer; affected range 1.0.3 through 1.2.0; the fix returns error -17), adds the Broccoli2Shell name, the three ways untrusted Brotli arrives (fetch, request bodies, direct calls), Python specifics and the scanner gap, which language ports are unaffected, exploitation status, and a survey of projects that bundle their own copy (.NET, DuckDB, ClickHouse, Arrow, the 7-Zip forks and more), with what is fixed and what is not as of 25 October. - PHP session audit: records the PHP Foundation's 23 October position on CVE-2026-115560 (full advisory with the next release, affected versions and severity not yet published, no exploitation reported, keep
session.upload_progress.enabledoff), and corrects one table cell that wrote the directive assession.upload_progresswithout.enabled. - Node.js guard documentation: adds the request-body path (Express 5.0.0 to 5.3.0, body-parser 2.0.0 to 2.3.0), how to read the bundled Brotli version, Imperva's reproduction on the official Node.js 24.22.0 image, and the restart and rebuild reminder.
2026-10-24
Added
- PHP2Shell on cPanel: check, drop-in, status, restore and cleanup for EasyApache 4 PHP (
ea-php74toea-php85) under any handler, with patch detection and a check that the web server and FPM workers have restarted. - PHP2Shell edge guards: Apache and nginx configuration that refuses multipart POSTs to paths you have not allowlisted (log-only first), cuts an oversized
Set-Cookieon Apache, and documents request body and response header limits for both servers. - PHP2Shell detection rules: an auditd rule, a Tetragon filter and a log-only outbound-connection rule that record every program the web-server account starts, with a guide to how strong each signal is.
- curl HTTP/2 upload: check for CVE-2026-92392 (fixed in 8.23.0; branch backports 8.14.3 / 8.16.2 / 8.20.2).
- nginx October 2026: check and
nginx -Tconfig audit for the five flaws fixed in 1.30.6 / 1.31.7, plus the two njs fixes in 1.0.2. - Nextcloud Collabora Built-in CODE: mitigation, check and hunt for CVE-2026-110447 (exploited in the wild). Update to 26.4.303 or remove; disabling is not enough.
- LiteLLM 1.107.0 supply-chain compromise: detect, hunt and contain the malicious release (no CVE). Pin 1.106.2 and treat an affected host as compromised.
- Plex Media Server Plex2Shell: check and hunt for the RCE chain (CVE-2026-96651/96652/96654/96655/96656) fixed in 1.43.3.10861, exploited in the wild to drop miners and a proxy backdoor.
- GhostAction developer-machine stealer: scan, hunt and contain the stage-2 stealer hidden in a fake
fa-solid-400.woff2and a VS CodefolderOpentask (no CVE, exploited in the wild).
Changed
- PHP2Shell edge guards: notes on how the guards behave across stacks.
mod_proxy_fcgirejects a leak-sized response on its own before the guard runs,proxy_buffer_sizebehaves the same asfastcgi_buffer_size, and HTTP/2 cannot run undermod_phpbecausemod_http2declines to operate under thepreforkMPM. - PHP2Shell detection rules: the nftables egress rule was loaded on a live system and logged a real DNS lookup and outbound connection made by the web account, and did not log the same traffic from another account.
- PHP2Shell hunt: the hunt baseline moved from the 21 October patch date to 17 October, the earliest exploitation date reported (by Amazon Threat Intelligence), so a quiet-period comparison is more likely to be quiet. Set
HUNT_SINCEto override (php2shell-mitigate.sh5.2.5). - PHP2Shell hunt and watch: indicators from a 24 October honeypot report, including both forms of the numbered-request fingerprint, leak-sized response leads, nginx's
upstream sent too big headererror, TCP peers of flagged processes, an attempt-only address list, proof files, and auditd events (php2shell-mitigate.sh5.2.4,php2shell-watch.sh1.4.3). - PHP2Shell exploitability summary: a sourced summary of what PHP validated (remote code execution over
mod_phpfor CVE-2026-109618 and over PHP-FPM for CVE-2026-109619, a likely first exploitation attempt on 17 October, reported by Amazon) and PHP's protective measures with their costs. The AppArmor layer does not reachmod_php. - Help and version handling: every script accepts
--help,--versionandversion, and rejects an unknown command. - Brotli checker: 1.2.0 also detects Python
brotlicffi(fixed 1.2.1.0) and cdxgen (fixed 13.5.0 / 12.8.9), and recognizes Debian 13's fixedbrotlibuild.
2026-10-23
Added
- Brotli checker: CVE-2026-111497 is not only a Node.js bug. The checker covers
libbrotlion the host, the runtimes that bundle it, and containers. - libheif checker: the HEIF/AVIF decoder heap overflow used to breach a Discourse forum. Read-only check plus ImageMagick and MediaWiki hardening.
- Ruby and GitLab checker: the Regexp fixes in Ruby 4.0.9 / 3.4.12 / 3.3.13 and the four GitLab CVEs. If you run GitLab, upgrade it first.
Changed
- PHP2Shell: CVE-2026-115560 (session upload progress) is not fixed by the 21 October releases. v5 keeps upload progress off after
cleanup. If you rancleanupwith v4, re-run it with v5. - php2shell-watch: adds two ReliaQuest detection signals for CVE-2026-109618 (
in Unknown on line 0, and a POST-500 / same-PID crash correlation).
2026-10-22
Changed
- PHP2Shell: an allocator double-free reproduced on 8.5.12 (the release listed as fixed) via
php -S.huntand the watcher now detect it. The AppArmor layer confines PHP-FPM, not thephpCLI.
2026-10-21
Added
- PHP2Shell mitigation:
php2shell-mitigate.shfor CVE-2026-109618 and CVE-2026-109619, written the night of 20 October, after exploit details leaked, then tested and published the morning of 21 October, before PHP published its fixes (announced for 14:00 UTC) and before distributions shipped theirs. Adds two layers to every installed PHP-FPM from 7.0 through 8.5: an ini drop-in that turns offsession.upload_progress, and an AppArmor profile, built from each version's own FPM config, that stops FPM from executing shells and other binaries. It syntax-checks each profile, tests FPM with a config check, restart, reload and socket check, and falls back to complain mode or unloads the profile if FPM does not come up. - PHP2Shell patch detection: added when PHP released the fixed versions (8.2.35, 8.3.36, 8.4.27 and 8.5.12) at 14:00 UTC (10:00 Eastern). The report,
statusandcleanupsay whether each installed PHP package is fixed, by upstream version, by known distribution backport, or by a package changelog that names both CVEs, and flag FPM or Apache still running the old binary after an update.cleanupremoves the ini drop-in once patched and leaves the AppArmor profile loaded.
The Security Patches software and this documentation are dedicated to the public domain under CC0 1.0 Universal. Other pages on privacysafe.app/docs are CC BY-SA 4.0 unless the page says otherwise.