phpwarden 2.3.0__tar.gz → 2.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {phpwarden-2.3.0 → phpwarden-2.5.0}/PKG-INFO +57 -21
- {phpwarden-2.3.0 → phpwarden-2.5.0}/README.md +54 -18
- {phpwarden-2.3.0 → phpwarden-2.5.0}/pyproject.toml +4 -4
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/__init__.py +1 -1
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/cli.py +104 -3
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/probe.py +301 -11
- phpwarden-2.5.0/src/phpwarden/sast/dbflow.py +941 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/engine.py +11 -4
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/taint.py +50 -3
- phpwarden-2.5.0/src/phpwarden/shield/EDGE.md +108 -0
- phpwarden-2.5.0/src/phpwarden/shield/README.md +98 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/shield/agent/phpwarden-shield.php +237 -7
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/shield/policy.py +56 -10
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/shield/report.py +19 -3
- phpwarden-2.5.0/src/phpwarden/thirdparty/__init__.py +1 -0
- phpwarden-2.5.0/src/phpwarden/thirdparty/trivy.py +188 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/verdict.py +56 -4
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden.egg-info/PKG-INFO +57 -21
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden.egg-info/SOURCES.txt +8 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_account_deletion.py +5 -2
- phpwarden-2.5.0/tests/test_probe_auth.py +308 -0
- phpwarden-2.5.0/tests/test_sast_dbflow.py +132 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_shield_dashboard.py +9 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_shield_runtime.py +155 -0
- phpwarden-2.5.0/tests/test_trivy_import.py +131 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/LICENSE +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/setup.cfg +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/code.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/code_rules.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/data/php-cve-feed.json +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/deps.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/detect.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/engine.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/env.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/feed.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/guard.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/integrity.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/report.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/rules.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sarif.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/__init__.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/ast.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/authz.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/callgraph.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/lexer.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/models/__init__.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/models/laravel.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/models/php_builtins.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/models/symfony.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/models/wordpress.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/parser.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/project.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/symbols.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/sast/types.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/shield/__init__.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/shield/library.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/shield/matcher.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/version.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/vulndb.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden/wordpress.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden.egg-info/dependency_links.txt +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden.egg-info/entry_points.txt +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/src/phpwarden.egg-info/top_level.txt +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_accounts.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_advisories.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_agency.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_assess.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_assignment.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_audit.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_billing.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_business_metrics.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_cli_edges.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_code.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_connect_flow.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_dashboard_states.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_deps_and_rules.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_detection_validation.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_developer.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_discussion.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_e2e_readiness.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_email.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_engine.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_engine_feed.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_feed_license.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_feed_subscription.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_fleet.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_free_feed.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_google_oauth.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_guard_live.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_integrity.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_kev_alert.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_kev_gaps.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_livefeed.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_mentions.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_probe.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_probe_cli.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_probe_dashboard.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_reachability.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_report_proof.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_saas.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_saas_billing.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_sarif.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_sast_layer5.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_sast_models.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_sast_parser.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_sast_project.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_sast_taint.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_server.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_settings.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_shield.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_shield_cli.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_shield_plan.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_slack.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_sso.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_store_connections.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_team.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_triage.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_waf_dryrun.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_webhook_idempotency.py +0 -0
- {phpwarden-2.3.0 → phpwarden-2.5.0}/tests/test_wordpress_and_report.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: phpwarden
|
|
3
|
-
Version: 2.
|
|
4
|
-
Summary: PHP vulnerability scanner for the PHP engine, Composer, WordPress, your own code and the live site. Ranked by real-world exploitation (CISA KEV, then EPSS), not CVSS. Offline, zero dependencies.
|
|
3
|
+
Version: 2.5.0
|
|
4
|
+
Summary: PHP vulnerability scanner for the PHP engine, Composer, WordPress, your own code and the live site. Ranked by real-world exploitation (CISA KEV, then EPSS), not CVSS; blocks exploits inside PHP (shield). Offline, zero dependencies.
|
|
5
5
|
Author: oroma-alfred
|
|
6
6
|
License-Expression: Apache-2.0
|
|
7
7
|
Project-URL: Homepage, https://phpwarden.io
|
|
8
8
|
Project-URL: Source, https://github.com/oroma-alfred/phpwarden
|
|
9
9
|
Project-URL: Issues, https://github.com/oroma-alfred/phpwarden/issues
|
|
10
|
-
Keywords: php,composer,wordpress,php-fpm,security,vulnerability,cve,kev,epss,sca,scanner
|
|
10
|
+
Keywords: php,composer,wordpress,php-fpm,security,vulnerability,cve,kev,epss,sca,sast,waf,scanner
|
|
11
11
|
Classifier: Development Status :: 4 - Beta
|
|
12
12
|
Classifier: Environment :: Console
|
|
13
13
|
Classifier: Intended Audience :: System Administrators
|
|
@@ -28,8 +28,9 @@ exploited (CISA KEV, as of 2026-11-14). phpwarden puts those first, then sorts
|
|
|
28
28
|
by EPSS probability, then CVSS — so a `composer.lock` with 30 findings tells
|
|
29
29
|
you which one to fix today.
|
|
30
30
|
|
|
31
|
-
It scans the PHP engine/FPM version, Composer dependencies
|
|
32
|
-
|
|
31
|
+
It scans the PHP engine/FPM version, Composer dependencies, WordPress installs
|
|
32
|
+
and your own PHP code, checks live sites from outside, and can block exploits
|
|
33
|
+
inside PHP, against one bundled, offline advisory feed. Zero runtime dependencies
|
|
33
34
|
(Python 3.8+), Apache-2.0.
|
|
34
35
|
|
|
35
36
|
**Reproducible benchmark:** on four real PHP stacks, phpwarden found 295 of 295
|
|
@@ -141,10 +142,44 @@ files / high or critical `code` and `probe` findings (`probe` also on any
|
|
|
141
142
|
known-exploited finding) / anything to act on now or this week (`assess`),
|
|
142
143
|
`2` possibly exposed (`scan`), `3` PHP version unknown (`scan`), `4` input
|
|
143
144
|
error, `5` `--report-to` upload failed on an otherwise clean run, `64` usage
|
|
144
|
-
error. Full table: `phpwarden --help`.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
## New in 2.3.0 and 2.2
|
|
145
|
+
error. `1` also means `feed update` failed. Full table: `phpwarden --help`.
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
## New in 2.5.0, 2.4.0, 2.3.0 and 2.2
|
|
149
|
+
|
|
150
|
+
- **2.5.0: live check behind a login.** On a site that has proved ownership,
|
|
151
|
+
`probe --cookie` / `--cookie-file` / `--header` (or a saved test-account login
|
|
152
|
+
on the dashboard, one same-origin login POST) repeats a few read-only requests
|
|
153
|
+
signed in: on WordPress, `/wp-admin/` (version) and `plugins.php` (plugin
|
|
154
|
+
versions). Logout, delete and nonce URLs are never requested; credential values
|
|
155
|
+
are never printed or logged, are stored encrypted (AES-256-GCM) and are deleted
|
|
156
|
+
with the project. Use a low-privilege test account. [Docs](https://phpwarden.io/docs#probe-auth).
|
|
157
|
+
- **2.5.0: PhpStorm plugin** in `integrations/phpstorm-plugin`, at parity with
|
|
158
|
+
the VS Code extension. Not on JetBrains Marketplace yet: build it and install
|
|
159
|
+
from disk.
|
|
160
|
+
- **2.5.0: `phpwarden code` resolves table names fixed in the code** (constants,
|
|
161
|
+
`define()`, Laravel `config()`, Symfony parameters, concatenation, `$wpdb->prefix`
|
|
162
|
+
and core table properties, Eloquent `$table`), closing the dynamic-table-name
|
|
163
|
+
limit of 2.4.0. Benchmark results are unchanged.
|
|
164
|
+
|
|
165
|
+
- **2.4.0: `phpwarden code` follows data through the database and callbacks.**
|
|
166
|
+
Request data saved with raw SQL, `$wpdb`, Eloquent, the query builder or
|
|
167
|
+
Doctrine and read back from the same table is traced to where it is printed
|
|
168
|
+
or queried (stored XSS, second-order SQL injection), and callbacks passed to
|
|
169
|
+
`array_map`, `usort`, `preg_replace_callback`, `add_filter` and the like,
|
|
170
|
+
`$f()` and first-class callables are followed. DVWA: 8/8/7 of 8 types under
|
|
171
|
+
the comparison's scorer (was 7/7/6); clean-code counts unchanged.
|
|
172
|
+
- **2.4.0: shield rate limits.** Per-client limits on WordPress login, password
|
|
173
|
+
reset, xmlrpc and `system.multicall`, Laravel login and reset, component
|
|
174
|
+
writes, and a burst guard. Log-only until promoted, then 429; APCu or file
|
|
175
|
+
store; fails open. `--trust-proxy CIDR`, `--no-limits`, `--limit-path REGEX`.
|
|
176
|
+
0 trips on 6,000 ordinary requests; 6 of 6 abuse scenarios caught. Pairing
|
|
177
|
+
with Cloudflare or nginx: [EDGE.md](src/phpwarden/shield/EDGE.md).
|
|
178
|
+
- **2.4.0: `phpwarden trivy-import` and `assess --trivy FILE` / `--run-trivy`.**
|
|
179
|
+
Trivy's JSON (npm/JS, OS packages, images, IaC, secrets) in the same ranked
|
|
180
|
+
list as PHP findings: KEV, then EPSS (`--kev`, `--epss`), then severity.
|
|
181
|
+
Secrets by file and line only. Never downloads Trivy. See
|
|
182
|
+
[src/phpwarden/thirdparty/README.md](src/phpwarden/thirdparty/README.md).
|
|
148
183
|
|
|
149
184
|
- **`phpwarden probe URL`**: a live check of a running site using GET and HEAD
|
|
150
185
|
requests only. It looks for exposed files (`.env`, `.git`, backups), open debug
|
|
@@ -158,14 +193,13 @@ error. Full table: `phpwarden --help`.
|
|
|
158
193
|
includes, redirects and HTTP clients, with a trace per finding (SARIF
|
|
159
194
|
`codeFlows`). Models Laravel, Symfony and WordPress: routes with no auth check,
|
|
160
195
|
mass assignment, raw Blade/Twig output, IDOR hints, CSRF exclusions, nonces.
|
|
161
|
-
Follows data stored in the session or WordPress options (second-order).
|
|
162
|
-
89 rules.
|
|
196
|
+
Follows data stored in the session or WordPress options, and (2.4.0; names resolved in 2.5.0) data saved to database tables (second-order), matched by table name: literal names, constants, Laravel config / Symfony parameters, `$wpdb->prefix` + name, `$wpdb->posts` etc. and Eloquent `$table` are resolved; table names built from run-time data are not matched.
|
|
197
|
+
89 rules. In our published comparison (2026-11-15) it found more than Semgrep, Psalm and Snyk Code, with far
|
|
163
198
|
fewer findings on clean framework code ([comparison](https://github.com/oroma-alfred/phpwarden/tree/main/bench/sast-compare-2026-11)).
|
|
164
|
-
Data that round-trips through the database is not followed.
|
|
165
199
|
- **`phpwarden shield`**: one PHP file loaded before your app that blocks exploit
|
|
166
200
|
attempts against the exploited vulnerabilities this site actually has, scoped
|
|
167
201
|
to their entry points. Logs until you promote rules (7-day burn-in, explicit
|
|
168
|
-
flag), fails open, has a kill switch, about 0.
|
|
202
|
+
flag), fails open, has a kill switch, about 0.1 ms per request in our benchmark. Not an edge
|
|
169
203
|
WAF: no DDoS, bot or TLS handling.
|
|
170
204
|
- **`phpwarden assess`**: one ranked list from every view of a site: installed
|
|
171
205
|
versions, your code, the live site from outside, and the access log, with the
|
|
@@ -180,9 +214,11 @@ error. Full table: `phpwarden --help`.
|
|
|
180
214
|
- **Coverage commitment**: in-scope CISA KEV entries are in the maintained feed
|
|
181
215
|
within 24 hours of listing, checked on every rebuild and published at
|
|
182
216
|
https://phpwarden.io/feeds/kev-status.json. Details: https://phpwarden.io/sla
|
|
183
|
-
- **Editors**: a VS Code extension
|
|
184
|
-
|
|
185
|
-
`integrations/
|
|
217
|
+
- **Editors**: a VS Code extension on the
|
|
218
|
+
[Marketplace](https://marketplace.visualstudio.com/items?itemName=phpwarden.phpwarden)
|
|
219
|
+
(`code --install-extension phpwarden.phpwarden`; source in `integrations/vscode`) and a PhpStorm plugin
|
|
220
|
+
in `integrations/phpstorm-plugin` (not on JetBrains Marketplace yet: build it and
|
|
221
|
+
use Install Plugin from Disk; External Tool steps in `integrations/phpstorm`).
|
|
186
222
|
|
|
187
223
|
## Replacing Wordfence CLI
|
|
188
224
|
|
|
@@ -248,7 +284,7 @@ see [phpwarden/laravel](https://packagist.org/packages/phpwarden/laravel).
|
|
|
248
284
|
```yaml
|
|
249
285
|
repos:
|
|
250
286
|
- repo: https://github.com/oroma-alfred/phpwarden
|
|
251
|
-
rev: v2.
|
|
287
|
+
rev: v2.5.0 # pin to a tag with `pre-commit autoupdate`
|
|
252
288
|
hooks:
|
|
253
289
|
- id: phpwarden-deps
|
|
254
290
|
# args: ["--no-reachability"] # faster: skip the reachability pass
|
|
@@ -259,14 +295,14 @@ timer recipes are in [`docs/recipes.md`](docs/recipes.md).
|
|
|
259
295
|
|
|
260
296
|
## The feed
|
|
261
297
|
|
|
262
|
-
The bundled community feed (2026.11.
|
|
298
|
+
The bundled community feed (2026.11.14.2 in this release) works forever, offline:
|
|
263
299
|
|
|
264
300
|
- **~21,300 advisories**: ~8,800 Composer (from [OSV.dev](https://osv.dev) and
|
|
265
301
|
[FriendsOfPHP](https://github.com/FriendsOfPHP/security-advisories)),
|
|
266
302
|
~12,300 WordPress (from [NVD](https://nvd.nist.gov): plugin, core and theme),
|
|
267
|
-
and
|
|
268
|
-
fixed versions, exposure conditions and detection signatures. About
|
|
269
|
-
EPSS score;
|
|
303
|
+
and 146 PHP engine/FPM CVEs, including hand-curated entries with per-branch
|
|
304
|
+
fixed versions, exposure conditions and detection signatures. About 18,200 distinct vulnerabilities carry an
|
|
305
|
+
EPSS score; 54 distinct vulnerabilities were in KEV when this feed was built.
|
|
270
306
|
- **License-independent by construction.** Every source is open or
|
|
271
307
|
public-domain (OSV, NVD, FriendsOfPHP, php-src release notes, CISA KEV, FIRST EPSS). No commercial
|
|
272
308
|
vendor's feed is used, so coverage cannot be revoked or priced away.
|
|
@@ -6,8 +6,9 @@ exploited (CISA KEV, as of 2026-11-14). phpwarden puts those first, then sorts
|
|
|
6
6
|
by EPSS probability, then CVSS — so a `composer.lock` with 30 findings tells
|
|
7
7
|
you which one to fix today.
|
|
8
8
|
|
|
9
|
-
It scans the PHP engine/FPM version, Composer dependencies
|
|
10
|
-
|
|
9
|
+
It scans the PHP engine/FPM version, Composer dependencies, WordPress installs
|
|
10
|
+
and your own PHP code, checks live sites from outside, and can block exploits
|
|
11
|
+
inside PHP, against one bundled, offline advisory feed. Zero runtime dependencies
|
|
11
12
|
(Python 3.8+), Apache-2.0.
|
|
12
13
|
|
|
13
14
|
**Reproducible benchmark:** on four real PHP stacks, phpwarden found 295 of 295
|
|
@@ -119,10 +120,44 @@ files / high or critical `code` and `probe` findings (`probe` also on any
|
|
|
119
120
|
known-exploited finding) / anything to act on now or this week (`assess`),
|
|
120
121
|
`2` possibly exposed (`scan`), `3` PHP version unknown (`scan`), `4` input
|
|
121
122
|
error, `5` `--report-to` upload failed on an otherwise clean run, `64` usage
|
|
122
|
-
error. Full table: `phpwarden --help`.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
## New in 2.3.0 and 2.2
|
|
123
|
+
error. `1` also means `feed update` failed. Full table: `phpwarden --help`.
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
## New in 2.5.0, 2.4.0, 2.3.0 and 2.2
|
|
127
|
+
|
|
128
|
+
- **2.5.0: live check behind a login.** On a site that has proved ownership,
|
|
129
|
+
`probe --cookie` / `--cookie-file` / `--header` (or a saved test-account login
|
|
130
|
+
on the dashboard, one same-origin login POST) repeats a few read-only requests
|
|
131
|
+
signed in: on WordPress, `/wp-admin/` (version) and `plugins.php` (plugin
|
|
132
|
+
versions). Logout, delete and nonce URLs are never requested; credential values
|
|
133
|
+
are never printed or logged, are stored encrypted (AES-256-GCM) and are deleted
|
|
134
|
+
with the project. Use a low-privilege test account. [Docs](https://phpwarden.io/docs#probe-auth).
|
|
135
|
+
- **2.5.0: PhpStorm plugin** in `integrations/phpstorm-plugin`, at parity with
|
|
136
|
+
the VS Code extension. Not on JetBrains Marketplace yet: build it and install
|
|
137
|
+
from disk.
|
|
138
|
+
- **2.5.0: `phpwarden code` resolves table names fixed in the code** (constants,
|
|
139
|
+
`define()`, Laravel `config()`, Symfony parameters, concatenation, `$wpdb->prefix`
|
|
140
|
+
and core table properties, Eloquent `$table`), closing the dynamic-table-name
|
|
141
|
+
limit of 2.4.0. Benchmark results are unchanged.
|
|
142
|
+
|
|
143
|
+
- **2.4.0: `phpwarden code` follows data through the database and callbacks.**
|
|
144
|
+
Request data saved with raw SQL, `$wpdb`, Eloquent, the query builder or
|
|
145
|
+
Doctrine and read back from the same table is traced to where it is printed
|
|
146
|
+
or queried (stored XSS, second-order SQL injection), and callbacks passed to
|
|
147
|
+
`array_map`, `usort`, `preg_replace_callback`, `add_filter` and the like,
|
|
148
|
+
`$f()` and first-class callables are followed. DVWA: 8/8/7 of 8 types under
|
|
149
|
+
the comparison's scorer (was 7/7/6); clean-code counts unchanged.
|
|
150
|
+
- **2.4.0: shield rate limits.** Per-client limits on WordPress login, password
|
|
151
|
+
reset, xmlrpc and `system.multicall`, Laravel login and reset, component
|
|
152
|
+
writes, and a burst guard. Log-only until promoted, then 429; APCu or file
|
|
153
|
+
store; fails open. `--trust-proxy CIDR`, `--no-limits`, `--limit-path REGEX`.
|
|
154
|
+
0 trips on 6,000 ordinary requests; 6 of 6 abuse scenarios caught. Pairing
|
|
155
|
+
with Cloudflare or nginx: [EDGE.md](src/phpwarden/shield/EDGE.md).
|
|
156
|
+
- **2.4.0: `phpwarden trivy-import` and `assess --trivy FILE` / `--run-trivy`.**
|
|
157
|
+
Trivy's JSON (npm/JS, OS packages, images, IaC, secrets) in the same ranked
|
|
158
|
+
list as PHP findings: KEV, then EPSS (`--kev`, `--epss`), then severity.
|
|
159
|
+
Secrets by file and line only. Never downloads Trivy. See
|
|
160
|
+
[src/phpwarden/thirdparty/README.md](src/phpwarden/thirdparty/README.md).
|
|
126
161
|
|
|
127
162
|
- **`phpwarden probe URL`**: a live check of a running site using GET and HEAD
|
|
128
163
|
requests only. It looks for exposed files (`.env`, `.git`, backups), open debug
|
|
@@ -136,14 +171,13 @@ error. Full table: `phpwarden --help`.
|
|
|
136
171
|
includes, redirects and HTTP clients, with a trace per finding (SARIF
|
|
137
172
|
`codeFlows`). Models Laravel, Symfony and WordPress: routes with no auth check,
|
|
138
173
|
mass assignment, raw Blade/Twig output, IDOR hints, CSRF exclusions, nonces.
|
|
139
|
-
Follows data stored in the session or WordPress options (second-order).
|
|
140
|
-
89 rules.
|
|
174
|
+
Follows data stored in the session or WordPress options, and (2.4.0; names resolved in 2.5.0) data saved to database tables (second-order), matched by table name: literal names, constants, Laravel config / Symfony parameters, `$wpdb->prefix` + name, `$wpdb->posts` etc. and Eloquent `$table` are resolved; table names built from run-time data are not matched.
|
|
175
|
+
89 rules. In our published comparison (2026-11-15) it found more than Semgrep, Psalm and Snyk Code, with far
|
|
141
176
|
fewer findings on clean framework code ([comparison](https://github.com/oroma-alfred/phpwarden/tree/main/bench/sast-compare-2026-11)).
|
|
142
|
-
Data that round-trips through the database is not followed.
|
|
143
177
|
- **`phpwarden shield`**: one PHP file loaded before your app that blocks exploit
|
|
144
178
|
attempts against the exploited vulnerabilities this site actually has, scoped
|
|
145
179
|
to their entry points. Logs until you promote rules (7-day burn-in, explicit
|
|
146
|
-
flag), fails open, has a kill switch, about 0.
|
|
180
|
+
flag), fails open, has a kill switch, about 0.1 ms per request in our benchmark. Not an edge
|
|
147
181
|
WAF: no DDoS, bot or TLS handling.
|
|
148
182
|
- **`phpwarden assess`**: one ranked list from every view of a site: installed
|
|
149
183
|
versions, your code, the live site from outside, and the access log, with the
|
|
@@ -158,9 +192,11 @@ error. Full table: `phpwarden --help`.
|
|
|
158
192
|
- **Coverage commitment**: in-scope CISA KEV entries are in the maintained feed
|
|
159
193
|
within 24 hours of listing, checked on every rebuild and published at
|
|
160
194
|
https://phpwarden.io/feeds/kev-status.json. Details: https://phpwarden.io/sla
|
|
161
|
-
- **Editors**: a VS Code extension
|
|
162
|
-
|
|
163
|
-
`integrations/
|
|
195
|
+
- **Editors**: a VS Code extension on the
|
|
196
|
+
[Marketplace](https://marketplace.visualstudio.com/items?itemName=phpwarden.phpwarden)
|
|
197
|
+
(`code --install-extension phpwarden.phpwarden`; source in `integrations/vscode`) and a PhpStorm plugin
|
|
198
|
+
in `integrations/phpstorm-plugin` (not on JetBrains Marketplace yet: build it and
|
|
199
|
+
use Install Plugin from Disk; External Tool steps in `integrations/phpstorm`).
|
|
164
200
|
|
|
165
201
|
## Replacing Wordfence CLI
|
|
166
202
|
|
|
@@ -226,7 +262,7 @@ see [phpwarden/laravel](https://packagist.org/packages/phpwarden/laravel).
|
|
|
226
262
|
```yaml
|
|
227
263
|
repos:
|
|
228
264
|
- repo: https://github.com/oroma-alfred/phpwarden
|
|
229
|
-
rev: v2.
|
|
265
|
+
rev: v2.5.0 # pin to a tag with `pre-commit autoupdate`
|
|
230
266
|
hooks:
|
|
231
267
|
- id: phpwarden-deps
|
|
232
268
|
# args: ["--no-reachability"] # faster: skip the reachability pass
|
|
@@ -237,14 +273,14 @@ timer recipes are in [`docs/recipes.md`](docs/recipes.md).
|
|
|
237
273
|
|
|
238
274
|
## The feed
|
|
239
275
|
|
|
240
|
-
The bundled community feed (2026.11.
|
|
276
|
+
The bundled community feed (2026.11.14.2 in this release) works forever, offline:
|
|
241
277
|
|
|
242
278
|
- **~21,300 advisories**: ~8,800 Composer (from [OSV.dev](https://osv.dev) and
|
|
243
279
|
[FriendsOfPHP](https://github.com/FriendsOfPHP/security-advisories)),
|
|
244
280
|
~12,300 WordPress (from [NVD](https://nvd.nist.gov): plugin, core and theme),
|
|
245
|
-
and
|
|
246
|
-
fixed versions, exposure conditions and detection signatures. About
|
|
247
|
-
EPSS score;
|
|
281
|
+
and 146 PHP engine/FPM CVEs, including hand-curated entries with per-branch
|
|
282
|
+
fixed versions, exposure conditions and detection signatures. About 18,200 distinct vulnerabilities carry an
|
|
283
|
+
EPSS score; 54 distinct vulnerabilities were in KEV when this feed was built.
|
|
248
284
|
- **License-independent by construction.** Every source is open or
|
|
249
285
|
public-domain (OSV, NVD, FriendsOfPHP, php-src release notes, CISA KEV, FIRST EPSS). No commercial
|
|
250
286
|
vendor's feed is used, so coverage cannot be revoked or priced away.
|
|
@@ -4,14 +4,14 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "phpwarden"
|
|
7
|
-
version = "2.
|
|
8
|
-
description = "PHP vulnerability scanner for the PHP engine, Composer, WordPress, your own code and the live site. Ranked by real-world exploitation (CISA KEV, then EPSS), not CVSS. Offline, zero dependencies."
|
|
7
|
+
version = "2.5.0"
|
|
8
|
+
description = "PHP vulnerability scanner for the PHP engine, Composer, WordPress, your own code and the live site. Ranked by real-world exploitation (CISA KEV, then EPSS), not CVSS; blocks exploits inside PHP (shield). Offline, zero dependencies."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
license-files = ["LICENSE"]
|
|
13
13
|
authors = [{ name = "oroma-alfred" }]
|
|
14
|
-
keywords = ["php", "composer", "wordpress", "php-fpm", "security", "vulnerability", "cve", "kev", "epss", "sca", "scanner"]
|
|
14
|
+
keywords = ["php", "composer", "wordpress", "php-fpm", "security", "vulnerability", "cve", "kev", "epss", "sca", "sast", "waf", "scanner"]
|
|
15
15
|
classifiers = [
|
|
16
16
|
"Development Status :: 4 - Beta",
|
|
17
17
|
"Environment :: Console",
|
|
@@ -39,4 +39,4 @@ package-dir = { "" = "src" }
|
|
|
39
39
|
where = ["src"]
|
|
40
40
|
|
|
41
41
|
[tool.setuptools.package-data]
|
|
42
|
-
phpwarden = ["data/*.json", "shield/agent/*.php"]
|
|
42
|
+
phpwarden = ["data/*.json", "shield/agent/*.php", "shield/*.md"]
|
|
@@ -6,4 +6,4 @@ real-world exploitation (CISA KEV, then EPSS, then CVSS), and can watch PHP-FPM
|
|
|
6
6
|
for active exploitation. The engine and the bundled feed are open; free users
|
|
7
7
|
get weekly feed updates, and a subscription adds the feed rebuilt twice a day.
|
|
8
8
|
"""
|
|
9
|
-
__version__ = "2.
|
|
9
|
+
__version__ = "2.5.0"
|
|
@@ -455,8 +455,32 @@ def _probe(args):
|
|
|
455
455
|
f" 3. A tag in the homepage <head>:\n <meta name=\"phpwarden-verify\" content=\"{token}\">\n\n"
|
|
456
456
|
f"Without it, probe only reads the homepage response (passive mode).")
|
|
457
457
|
return 0
|
|
458
|
+
auth = None
|
|
459
|
+
if args.cookie or args.cookie_file or args.header:
|
|
460
|
+
if args.passive:
|
|
461
|
+
sys.stderr.write("error: --cookie/--cookie-file need the active checks; drop --passive\n")
|
|
462
|
+
return 4
|
|
463
|
+
try:
|
|
464
|
+
raw = list(args.cookie or [])
|
|
465
|
+
if args.cookie_file:
|
|
466
|
+
with open(args.cookie_file, encoding="utf-8") as fh:
|
|
467
|
+
raw.append(fh.read())
|
|
468
|
+
cookies = {}
|
|
469
|
+
for r in raw:
|
|
470
|
+
cookies.update(pr.parse_cookies(r))
|
|
471
|
+
headers = {}
|
|
472
|
+
for hv in args.header or []:
|
|
473
|
+
k, sep, v = hv.partition(":")
|
|
474
|
+
if not sep:
|
|
475
|
+
raise ValueError("header must be 'Name: value'")
|
|
476
|
+
headers[k.strip()] = v.strip()
|
|
477
|
+
auth = pr.Auth(cookies=cookies, headers=headers)
|
|
478
|
+
except (OSError, ValueError) as e: # messages never contain the cookie value
|
|
479
|
+
sys.stderr.write(f"error: could not read the cookie: {e.__class__.__name__}"
|
|
480
|
+
f"{'' if isinstance(e, OSError) else ': ' + str(e)}\n")
|
|
481
|
+
return 4
|
|
458
482
|
res = pr.run_probe(url, token=token, active=False if args.passive else None,
|
|
459
|
-
max_requests=args.max_requests)
|
|
483
|
+
max_requests=args.max_requests, auth=auth)
|
|
460
484
|
if args.json:
|
|
461
485
|
print(json.dumps(res, indent=2))
|
|
462
486
|
elif _fmt(args) == "sarif":
|
|
@@ -546,8 +570,29 @@ def _assess(args):
|
|
|
546
570
|
if any("homepage unreachable" in n for n in probe_result.get("notes", [])):
|
|
547
571
|
sys.stderr.write(f"error: could not reach {url}\n")
|
|
548
572
|
return 4
|
|
573
|
+
trivy_fs, trivy_note = None, None
|
|
574
|
+
if args.trivy or args.run_trivy:
|
|
575
|
+
from phpwarden.thirdparty import trivy as tv
|
|
576
|
+
try:
|
|
577
|
+
kev, epss = tv.load_kev(args.kev), tv.load_epss(args.epss)
|
|
578
|
+
docs = [tv.load_report(f) for f in (args.trivy or [])]
|
|
579
|
+
except (OSError, ValueError) as e:
|
|
580
|
+
sys.stderr.write(f"error: {e}\n")
|
|
581
|
+
return 4
|
|
582
|
+
if args.run_trivy and args.path:
|
|
583
|
+
doc, msg = tv.run_trivy_fs(args.path)
|
|
584
|
+
if doc is not None:
|
|
585
|
+
docs.append(doc)
|
|
586
|
+
else:
|
|
587
|
+
trivy_note = msg
|
|
588
|
+
sys.stderr.write(msg + "\n")
|
|
589
|
+
trivy_fs = [f for d in docs for f in tv.findings(d, kev, epss)]
|
|
590
|
+
if docs and not (args.kev or args.epss):
|
|
591
|
+
trivy_note = (trivy_note + "; " if trivy_note else "") + \
|
|
592
|
+
"non-PHP findings ranked by severity only (pass --kev and --epss for exploitation data)"
|
|
549
593
|
try:
|
|
550
|
-
res = vd.assess(args.path, probe_result=probe_result, logfile=args.log, run_code=not args.no_code
|
|
594
|
+
res = vd.assess(args.path, probe_result=probe_result, logfile=args.log, run_code=not args.no_code,
|
|
595
|
+
trivy_findings=trivy_fs, trivy_note=trivy_note)
|
|
551
596
|
except OSError as e: # unreadable access log
|
|
552
597
|
sys.stderr.write(f"error: {e}\n")
|
|
553
598
|
return 4
|
|
@@ -563,6 +608,31 @@ def _assess(args):
|
|
|
563
608
|
return vd.exit_code(res)
|
|
564
609
|
|
|
565
610
|
|
|
611
|
+
def _trivy_import(args):
|
|
612
|
+
from phpwarden.thirdparty import trivy as tv
|
|
613
|
+
try:
|
|
614
|
+
kev, epss = tv.load_kev(args.kev), tv.load_epss(args.epss)
|
|
615
|
+
fs = [f for p in args.files for f in tv.findings(tv.load_report(p), kev, epss)]
|
|
616
|
+
except (OSError, ValueError) as e:
|
|
617
|
+
sys.stderr.write(f"error: {e}\n")
|
|
618
|
+
return 4
|
|
619
|
+
doc = tv.to_report_doc(fs, args.files)
|
|
620
|
+
if args.json:
|
|
621
|
+
print(json.dumps(doc, indent=2))
|
|
622
|
+
else:
|
|
623
|
+
kev_n = sum(1 for f in fs if f["known_exploited"])
|
|
624
|
+
print(f"{len(fs)} finding(s) from {len(args.files)} Trivy report(s); {kev_n} known exploited. "
|
|
625
|
+
f"Ranked by exploitation{'' if (args.kev or args.epss) else ' (no --kev/--epss: by severity)'}:")
|
|
626
|
+
for f in fs[:50]:
|
|
627
|
+
tag = " [KEV]" if f["known_exploited"] else (f" [EPSS {f['epss'] * 100:.0f}%]" if f.get("epss") else "")
|
|
628
|
+
dev = " (dev)" if f["dev"] else ""
|
|
629
|
+
print(f" {f['severity']:<8} {tv.ident(f)}{tag}{dev} {f['title'][:90]}")
|
|
630
|
+
if len(fs) > 50:
|
|
631
|
+
print(f" ... and {len(fs) - 50} more; use --json for all")
|
|
632
|
+
rc = 1 if any(f["known_exploited"] or f["severity"] in ("critical", "high") for f in fs) else 0
|
|
633
|
+
return _combine(rc, _maybe_report(args, doc))
|
|
634
|
+
|
|
635
|
+
|
|
566
636
|
def _shield(args):
|
|
567
637
|
from pathlib import Path as _P
|
|
568
638
|
from phpwarden.shield import policy as sp, report as sr
|
|
@@ -572,7 +642,9 @@ def _shield(args):
|
|
|
572
642
|
sys.stderr.write(f"error: not a directory: {args.path}\n")
|
|
573
643
|
return 4
|
|
574
644
|
pol = sp.build_policy_for_path(str(root), FeedManager().current(), php_version=args.php_version,
|
|
575
|
-
php_sapi=args.php_sapi, log_path=args.log
|
|
645
|
+
php_sapi=args.php_sapi, log_path=args.log,
|
|
646
|
+
limits=not args.no_limits, limit_paths=args.limit_path or [],
|
|
647
|
+
trust_proxy=args.trust_proxy or [])
|
|
576
648
|
out = args.out or "phpwarden-shield.policy.json"
|
|
577
649
|
j, php = sp.write_policy(pol, out)
|
|
578
650
|
if args.json:
|
|
@@ -754,6 +826,15 @@ def main(argv=None):
|
|
|
754
826
|
_report_args(wpc)
|
|
755
827
|
wpc.set_defaults(func=_wordpress)
|
|
756
828
|
|
|
829
|
+
tvi = sub.add_parser("trivy-import", help="read Trivy JSON reports (npm/JS, OS packages, images, IaC), "
|
|
830
|
+
"rank them by exploitation, optionally send them to the dashboard")
|
|
831
|
+
tvi.add_argument("files", nargs="+", metavar="TRIVY_JSON", help="output of trivy fs/image/config --format json")
|
|
832
|
+
tvi.add_argument("--kev", metavar="FILE", help="CISA KEV catalogue JSON")
|
|
833
|
+
tvi.add_argument("--epss", metavar="FILE", help="FIRST EPSS CSV (.csv or .csv.gz)")
|
|
834
|
+
tvi.add_argument("--json", action="store_true", help="machine-readable JSON output")
|
|
835
|
+
_report_args(tvi)
|
|
836
|
+
tvi.set_defaults(func=_trivy_import)
|
|
837
|
+
|
|
757
838
|
sh = sub.add_parser("shield", help="protection inside PHP: block exploits of the vulnerabilities this site "
|
|
758
839
|
"actually has (log-only until you promote rules)")
|
|
759
840
|
shs = sh.add_subparsers(dest="shield_cmd", required=True, parser_class=_Parser)
|
|
@@ -763,6 +844,12 @@ def main(argv=None):
|
|
|
763
844
|
shp.add_argument("--php-version", help="the production PHP version, for engine CVE rules")
|
|
764
845
|
shp.add_argument("--php-sapi", choices=["fpm", "cgi", "cli"], help="the production SAPI")
|
|
765
846
|
shp.add_argument("--log", help="where the agent should write its log (default: next to the agent)")
|
|
847
|
+
shp.add_argument("--no-limits", action="store_true",
|
|
848
|
+
help="leave out the rate limits (login, password reset, xmlrpc, burst guard)")
|
|
849
|
+
shp.add_argument("--limit-path", action="append", metavar="REGEX",
|
|
850
|
+
help="also rate-limit requests to this path (repeatable)")
|
|
851
|
+
shp.add_argument("--trust-proxy", action="append", metavar="CIDR",
|
|
852
|
+
help="trust forwarded client IPs only from this proxy range, e.g. your CDN (repeatable)")
|
|
766
853
|
shp.add_argument("--json", action="store_true", help="print the policy as JSON")
|
|
767
854
|
shi = shs.add_parser("install", help="show how to load the agent (and copy it with --dest)")
|
|
768
855
|
shi.add_argument("--dest", metavar="DIR", help="copy phpwarden-shield.php into this folder")
|
|
@@ -789,6 +876,12 @@ def main(argv=None):
|
|
|
789
876
|
asx.add_argument("--baseline", metavar="FILE",
|
|
790
877
|
help="an earlier --out file: report what is fixed and verified, still open, and new")
|
|
791
878
|
asx.add_argument("--json", action="store_true", help="machine-readable JSON output")
|
|
879
|
+
asx.add_argument("--trivy", metavar="FILE", action="append",
|
|
880
|
+
help="add a Trivy JSON report (npm/JS, OS packages, images, IaC); repeatable")
|
|
881
|
+
asx.add_argument("--run-trivy", action="store_true",
|
|
882
|
+
help="run `trivy fs` on the path if Trivy is installed (never downloads it)")
|
|
883
|
+
asx.add_argument("--kev", metavar="FILE", help="CISA KEV catalogue JSON, to rank non-PHP CVEs by exploitation")
|
|
884
|
+
asx.add_argument("--epss", metavar="FILE", help="FIRST EPSS CSV (.csv or .csv.gz) for non-PHP CVEs")
|
|
792
885
|
asx.set_defaults(func=_assess)
|
|
793
886
|
|
|
794
887
|
cd = sub.add_parser("code", help="scan your own PHP code for high-signal security bugs "
|
|
@@ -814,6 +907,14 @@ def main(argv=None):
|
|
|
814
907
|
help="show how to verify ownership of the site, then exit")
|
|
815
908
|
pb.add_argument("--passive", action="store_true", help="read the homepage response only")
|
|
816
909
|
pb.add_argument("--max-requests", type=int, default=60, help="request budget (default 60)")
|
|
910
|
+
pb.add_argument("--cookie", action="append", metavar="NAME=VALUE",
|
|
911
|
+
help="session cookie for the signed-in check (repeatable; used only after ownership is "
|
|
912
|
+
"verified, only on that site, GET/HEAD only; never printed). Use a low-privilege test account")
|
|
913
|
+
pb.add_argument("--cookie-file", metavar="FILE",
|
|
914
|
+
help="read cookies from FILE (name=value lines or a Netscape cookies.txt); keeps them out of "
|
|
915
|
+
"shell history")
|
|
916
|
+
pb.add_argument("--header", action="append", metavar="'NAME: VALUE'",
|
|
917
|
+
help="extra header sent with the signed-in requests (repeatable; never printed)")
|
|
817
918
|
pb.add_argument("--json", action="store_true", help="machine-readable JSON output")
|
|
818
919
|
_format_arg(pb)
|
|
819
920
|
pb.set_defaults(func=_probe)
|