phpwarden 2.0.3__tar.gz → 2.1.1__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.
Files changed (65) hide show
  1. {phpwarden-2.0.3 → phpwarden-2.1.1}/PKG-INFO +32 -7
  2. {phpwarden-2.0.3 → phpwarden-2.1.1}/README.md +31 -6
  3. {phpwarden-2.0.3 → phpwarden-2.1.1}/pyproject.toml +1 -1
  4. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden/__init__.py +1 -1
  5. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden/cli.py +41 -0
  6. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden/data/php-cve-feed.json +19978 -19692
  7. phpwarden-2.1.1/src/phpwarden/integrity.py +254 -0
  8. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden.egg-info/PKG-INFO +32 -7
  9. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden.egg-info/SOURCES.txt +7 -0
  10. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_advisories.py +123 -2
  11. phpwarden-2.1.1/tests/test_agency.py +321 -0
  12. phpwarden-2.1.1/tests/test_business_metrics.py +45 -0
  13. phpwarden-2.1.1/tests/test_integrity.py +109 -0
  14. phpwarden-2.1.1/tests/test_kev_gaps.py +23 -0
  15. phpwarden-2.1.1/tests/test_livefeed.py +76 -0
  16. phpwarden-2.1.1/tests/test_store_connections.py +40 -0
  17. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_wordpress_and_report.py +2 -1
  18. {phpwarden-2.0.3 → phpwarden-2.1.1}/LICENSE +0 -0
  19. {phpwarden-2.0.3 → phpwarden-2.1.1}/setup.cfg +0 -0
  20. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden/deps.py +0 -0
  21. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden/detect.py +0 -0
  22. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden/engine.py +0 -0
  23. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden/env.py +0 -0
  24. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden/feed.py +0 -0
  25. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden/guard.py +0 -0
  26. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden/report.py +0 -0
  27. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden/rules.py +0 -0
  28. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden/version.py +0 -0
  29. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden/vulndb.py +0 -0
  30. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden/wordpress.py +0 -0
  31. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden.egg-info/dependency_links.txt +0 -0
  32. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden.egg-info/entry_points.txt +0 -0
  33. {phpwarden-2.0.3 → phpwarden-2.1.1}/src/phpwarden.egg-info/top_level.txt +0 -0
  34. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_accounts.py +0 -0
  35. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_assignment.py +0 -0
  36. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_audit.py +0 -0
  37. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_billing.py +0 -0
  38. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_cli_edges.py +0 -0
  39. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_connect_flow.py +0 -0
  40. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_dashboard_states.py +0 -0
  41. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_deps_and_rules.py +0 -0
  42. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_detection_validation.py +0 -0
  43. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_developer.py +0 -0
  44. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_discussion.py +0 -0
  45. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_e2e_readiness.py +0 -0
  46. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_email.py +0 -0
  47. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_engine.py +0 -0
  48. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_engine_feed.py +0 -0
  49. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_feed_license.py +0 -0
  50. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_feed_subscription.py +0 -0
  51. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_fleet.py +0 -0
  52. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_google_oauth.py +0 -0
  53. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_guard_live.py +0 -0
  54. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_mentions.py +0 -0
  55. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_reachability.py +0 -0
  56. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_saas.py +0 -0
  57. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_saas_billing.py +0 -0
  58. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_server.py +0 -0
  59. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_settings.py +0 -0
  60. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_shield.py +0 -0
  61. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_slack.py +0 -0
  62. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_sso.py +0 -0
  63. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_team.py +0 -0
  64. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_triage.py +0 -0
  65. {phpwarden-2.0.3 → phpwarden-2.1.1}/tests/test_webhook_idempotency.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: phpwarden
3
- Version: 2.0.3
3
+ Version: 2.1.1
4
4
  Summary: PHP vulnerability scanner for Composer, WordPress and the PHP engine — findings ranked by real-world exploitation (CISA KEV, then EPSS), not CVSS. Offline, zero deps.
5
5
  Author: oroma-alfred
6
6
  License-Expression: Apache-2.0
@@ -23,8 +23,8 @@ Dynamic: license-file
23
23
  # phpwarden
24
24
 
25
25
  **PHP vulnerability scanner that ranks findings by real-world exploitation,
26
- not CVSS.** Of the ~21,100 PHP advisories in the feed, 43 are actually being
27
- exploited (CISA KEV, as of 2026-11-12). phpwarden puts those first, then sorts
26
+ not CVSS.** Of about 19,500 PHP vulnerabilities in the feed, 41 are known to be
27
+ exploited (CISA KEV, as of 2026-11-13). 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
 
@@ -32,6 +32,13 @@ It scans the PHP engine/FPM version, Composer dependencies and WordPress
32
32
  installs against one bundled, offline advisory feed. Zero runtime dependencies
33
33
  (Python 3.8+), Apache-2.0.
34
34
 
35
+ **Reproducible benchmark:** on four real PHP stacks, phpwarden found 295 of 295
36
+ known vulnerabilities, `composer audit` 286 and OSV.dev 262. Of 297 findings,
37
+ 100 were rated critical or high and 4 were actually exploited or likely to be;
38
+ phpwarden ranked each of those first or second in its project. Method, numbers
39
+ and a script to rerun it:
40
+ [the benchmark write-up](https://phpwarden.io/blog/phpwarden-vs-composer-audit-osv-2026-11).
41
+
35
42
  ```bash
36
43
  $ phpwarden deps composer.lock
37
44
  18 vulnerable package(s) in composer.lock; 0 actively exploited (KEV). Ranked by exploitation risk, then reachability:
@@ -51,6 +58,7 @@ $ phpwarden deps composer.lock
51
58
  | PHP engine / FPM CVE exposure | `scan` | image & network scanners |
52
59
  | Composer dependency CVEs | `deps` | Snyk, `composer audit` |
53
60
  | WordPress core, plugin and theme CVEs | `wordpress` | Patchstack, Wordfence |
61
+ | WordPress file integrity (wordpress.org checksums, injected files) | `integrity` | Wordfence CLI malware-scan (partly) |
54
62
  | Exploitation signatures in logs | `detect` | SIEM content |
55
63
  | WAF blocking rules (PHP-specific) | `rules` | the gap a generic WAF leaves |
56
64
  | Fleet exposure dashboard | `report` | the CNAPP's PHP view |
@@ -78,8 +86,9 @@ $ phpwarden deps composer.lock
78
86
  ```bash
79
87
  composer require --dev phpwarden/phpwarden # PHP projects → vendor/bin/phpwarden
80
88
  pipx install phpwarden # Python-tooling box
89
+ brew install oroma-alfred/tap/phpwarden # macOS / Linux with Homebrew
81
90
  python3 phpwarden.pyz scan # single file, no install
82
- docker build -t phpwarden . && docker run --rm phpwarden scan --version 8.3.10 --sapi fpm --os linux
91
+ docker run --rm phpwarden/phpwarden scan --version 8.3.10 --sapi fpm --os linux # Docker Hub, amd64 + arm64
83
92
  ```
84
93
 
85
94
  On modern macOS / Debian / Ubuntu a plain `pip install phpwarden` into the
@@ -90,8 +99,8 @@ system Python is blocked by [PEP 668](https://peps.python.org/pep-0668/); use
90
99
  python3 -m venv ~/.venvs/phpwarden && ~/.venvs/phpwarden/bin/pip install phpwarden
91
100
  ```
92
101
 
93
- Docker usage (mounted projects, CI, dashboard reporting) is in
94
- [`docs/docker.md`](docs/docker.md).
102
+ Docker usage (mounted projects, exit codes, CI, dashboard reporting) is on the
103
+ image's [Docker Hub page](https://hub.docker.com/r/phpwarden/phpwarden).
95
104
 
96
105
  ## Use
97
106
 
@@ -100,6 +109,7 @@ phpwarden scan # assess this host (auto-detects version/SA
100
109
  phpwarden scan --version 8.3.10 --sapi fpm --os linux
101
110
  phpwarden deps composer.lock # Composer dependencies, KEV → reachability → EPSS → CVSS
102
111
  phpwarden wordpress /var/www/html # WordPress core, plugins, themes
112
+ phpwarden integrity /var/www/html # tampered or injected files (vs wordpress.org checksums)
103
113
  phpwarden detect /var/log/nginx/access.log # exploit signatures in a log
104
114
  phpwarden rules --format nginx --out php-block.conf # PHP-specific WAF rules (or modsecurity)
105
115
  phpwarden report web01.json web02.json --out fleet.html # aggregate a fleet view
@@ -112,6 +122,21 @@ built for gating: `0` clean, `1` exposed / vulnerable / signature hits,
112
122
  error, `5` `--report-to` upload failed on an otherwise clean run, `64` usage
113
123
  error. Full table: `phpwarden --help`.
114
124
 
125
+
126
+ ## Replacing Wordfence CLI
127
+
128
+ Wordfence closed new licences for its CLI in October 2026; Free licences stopped working on 2026-10-14 and Premium
129
+ licences are not renewed. phpwarden runs the same way (on the server, no plugin in the site) and covers:
130
+
131
+ | Wordfence CLI | phpwarden | Notes |
132
+ |---|---|---|
133
+ | `wordfence vuln-scan /path` | `phpwarden wordpress /path` | Same job, ranked by real-world exploitation; JSON/SARIF and CI exit codes. Also scans Composer and the PHP engine. |
134
+ | `wordfence malware-scan /path` | `phpwarden integrity /path` | Compares core and wordpress.org plugin files with official checksums; flags injected files, PHP in uploads and common backdoor code. **Not a signature scanner**: premium plugins and themes cannot be verified and are listed as such. |
135
+ | `wordfence remediate` | – | Reinstall the flagged component with WP-CLI. |
136
+ | `wordfence db-scan` | – | Not covered. |
137
+
138
+ Full guide: https://phpwarden.io/compare/phpwarden-vs-wordfence-cli#replace
139
+
115
140
  ## Send results to the dashboard
116
141
 
117
142
  Any `scan`, `deps`, `wordpress` or `detect` run can post its result to
@@ -174,7 +199,7 @@ timer recipes are in [`docs/recipes.md`](docs/recipes.md).
174
199
 
175
200
  The bundled community feed (currently 2026.10.31.2) works forever, offline:
176
201
 
177
- - **~21,100 advisories**: ~8,600 Composer (from [OSV.dev](https://osv.dev) and
202
+ - **~21,300 advisories**: ~8,800 Composer (from [OSV.dev](https://osv.dev) and
178
203
  [FriendsOfPHP](https://github.com/FriendsOfPHP/security-advisories)),
179
204
  ~12,300 WordPress (from [NVD](https://nvd.nist.gov): plugin, core and theme),
180
205
  and 145 PHP engine/FPM CVEs, including hand-curated entries with per-branch
@@ -1,8 +1,8 @@
1
1
  # phpwarden
2
2
 
3
3
  **PHP vulnerability scanner that ranks findings by real-world exploitation,
4
- not CVSS.** Of the ~21,100 PHP advisories in the feed, 43 are actually being
5
- exploited (CISA KEV, as of 2026-11-12). phpwarden puts those first, then sorts
4
+ not CVSS.** Of about 19,500 PHP vulnerabilities in the feed, 41 are known to be
5
+ exploited (CISA KEV, as of 2026-11-13). 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
 
@@ -10,6 +10,13 @@ It scans the PHP engine/FPM version, Composer dependencies and WordPress
10
10
  installs against one bundled, offline advisory feed. Zero runtime dependencies
11
11
  (Python 3.8+), Apache-2.0.
12
12
 
13
+ **Reproducible benchmark:** on four real PHP stacks, phpwarden found 295 of 295
14
+ known vulnerabilities, `composer audit` 286 and OSV.dev 262. Of 297 findings,
15
+ 100 were rated critical or high and 4 were actually exploited or likely to be;
16
+ phpwarden ranked each of those first or second in its project. Method, numbers
17
+ and a script to rerun it:
18
+ [the benchmark write-up](https://phpwarden.io/blog/phpwarden-vs-composer-audit-osv-2026-11).
19
+
13
20
  ```bash
14
21
  $ phpwarden deps composer.lock
15
22
  18 vulnerable package(s) in composer.lock; 0 actively exploited (KEV). Ranked by exploitation risk, then reachability:
@@ -29,6 +36,7 @@ $ phpwarden deps composer.lock
29
36
  | PHP engine / FPM CVE exposure | `scan` | image & network scanners |
30
37
  | Composer dependency CVEs | `deps` | Snyk, `composer audit` |
31
38
  | WordPress core, plugin and theme CVEs | `wordpress` | Patchstack, Wordfence |
39
+ | WordPress file integrity (wordpress.org checksums, injected files) | `integrity` | Wordfence CLI malware-scan (partly) |
32
40
  | Exploitation signatures in logs | `detect` | SIEM content |
33
41
  | WAF blocking rules (PHP-specific) | `rules` | the gap a generic WAF leaves |
34
42
  | Fleet exposure dashboard | `report` | the CNAPP's PHP view |
@@ -56,8 +64,9 @@ $ phpwarden deps composer.lock
56
64
  ```bash
57
65
  composer require --dev phpwarden/phpwarden # PHP projects → vendor/bin/phpwarden
58
66
  pipx install phpwarden # Python-tooling box
67
+ brew install oroma-alfred/tap/phpwarden # macOS / Linux with Homebrew
59
68
  python3 phpwarden.pyz scan # single file, no install
60
- docker build -t phpwarden . && docker run --rm phpwarden scan --version 8.3.10 --sapi fpm --os linux
69
+ docker run --rm phpwarden/phpwarden scan --version 8.3.10 --sapi fpm --os linux # Docker Hub, amd64 + arm64
61
70
  ```
62
71
 
63
72
  On modern macOS / Debian / Ubuntu a plain `pip install phpwarden` into the
@@ -68,8 +77,8 @@ system Python is blocked by [PEP 668](https://peps.python.org/pep-0668/); use
68
77
  python3 -m venv ~/.venvs/phpwarden && ~/.venvs/phpwarden/bin/pip install phpwarden
69
78
  ```
70
79
 
71
- Docker usage (mounted projects, CI, dashboard reporting) is in
72
- [`docs/docker.md`](docs/docker.md).
80
+ Docker usage (mounted projects, exit codes, CI, dashboard reporting) is on the
81
+ image's [Docker Hub page](https://hub.docker.com/r/phpwarden/phpwarden).
73
82
 
74
83
  ## Use
75
84
 
@@ -78,6 +87,7 @@ phpwarden scan # assess this host (auto-detects version/SA
78
87
  phpwarden scan --version 8.3.10 --sapi fpm --os linux
79
88
  phpwarden deps composer.lock # Composer dependencies, KEV → reachability → EPSS → CVSS
80
89
  phpwarden wordpress /var/www/html # WordPress core, plugins, themes
90
+ phpwarden integrity /var/www/html # tampered or injected files (vs wordpress.org checksums)
81
91
  phpwarden detect /var/log/nginx/access.log # exploit signatures in a log
82
92
  phpwarden rules --format nginx --out php-block.conf # PHP-specific WAF rules (or modsecurity)
83
93
  phpwarden report web01.json web02.json --out fleet.html # aggregate a fleet view
@@ -90,6 +100,21 @@ built for gating: `0` clean, `1` exposed / vulnerable / signature hits,
90
100
  error, `5` `--report-to` upload failed on an otherwise clean run, `64` usage
91
101
  error. Full table: `phpwarden --help`.
92
102
 
103
+
104
+ ## Replacing Wordfence CLI
105
+
106
+ Wordfence closed new licences for its CLI in October 2026; Free licences stopped working on 2026-10-14 and Premium
107
+ licences are not renewed. phpwarden runs the same way (on the server, no plugin in the site) and covers:
108
+
109
+ | Wordfence CLI | phpwarden | Notes |
110
+ |---|---|---|
111
+ | `wordfence vuln-scan /path` | `phpwarden wordpress /path` | Same job, ranked by real-world exploitation; JSON/SARIF and CI exit codes. Also scans Composer and the PHP engine. |
112
+ | `wordfence malware-scan /path` | `phpwarden integrity /path` | Compares core and wordpress.org plugin files with official checksums; flags injected files, PHP in uploads and common backdoor code. **Not a signature scanner**: premium plugins and themes cannot be verified and are listed as such. |
113
+ | `wordfence remediate` | – | Reinstall the flagged component with WP-CLI. |
114
+ | `wordfence db-scan` | – | Not covered. |
115
+
116
+ Full guide: https://phpwarden.io/compare/phpwarden-vs-wordfence-cli#replace
117
+
93
118
  ## Send results to the dashboard
94
119
 
95
120
  Any `scan`, `deps`, `wordpress` or `detect` run can post its result to
@@ -152,7 +177,7 @@ timer recipes are in [`docs/recipes.md`](docs/recipes.md).
152
177
 
153
178
  The bundled community feed (currently 2026.10.31.2) works forever, offline:
154
179
 
155
- - **~21,100 advisories**: ~8,600 Composer (from [OSV.dev](https://osv.dev) and
180
+ - **~21,300 advisories**: ~8,800 Composer (from [OSV.dev](https://osv.dev) and
156
181
  [FriendsOfPHP](https://github.com/FriendsOfPHP/security-advisories)),
157
182
  ~12,300 WordPress (from [NVD](https://nvd.nist.gov): plugin, core and theme),
158
183
  and 145 PHP engine/FPM CVEs, including hand-curated entries with per-branch
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "phpwarden"
7
- version = "2.0.3"
7
+ version = "2.1.1"
8
8
  description = "PHP vulnerability scanner for Composer, WordPress and the PHP engine — findings ranked by real-world exploitation (CISA KEV, then EPSS), not CVSS. Offline, zero deps."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -5,4 +5,4 @@ environment against an evolving knowledge base of PHP CVEs (the feed), and can
5
5
  watch PHP-FPM for active exploitation. The engine is open; the CVE feed is the
6
6
  part a subscription keeps current.
7
7
  """
8
- __version__ = "2.0.3"
8
+ __version__ = "2.1.1"
@@ -372,6 +372,39 @@ def _wordpress(args):
372
372
  return _combine(1 if findings else 0, _maybe_report(args, doc))
373
373
 
374
374
 
375
+ def _integrity(args):
376
+ from phpwarden import integrity as integ
377
+ res = integ.check(args.path, locale=args.locale, plugins=not args.no_plugins)
378
+ doc = integ.to_doc(res)
379
+ if args.json:
380
+ print(json.dumps(doc, indent=2))
381
+ return 1 if res.tampered else 0
382
+ if not res.core_version:
383
+ print(f"{args.path}: no WordPress install detected at that path")
384
+ return 2
385
+ labels = {"php-in-uploads": "PHP file in uploads", "unexpected": "does not belong",
386
+ "modified": "modified", "missing": "missing"}
387
+ bad = [i for i in res.issues if i.kind != "missing"]
388
+ print(f"WordPress {res.core_version} at {args.path}: {res.files_checked} files compared with wordpress.org, "
389
+ f"{len(bad)} problem{'s' if len(bad) != 1 else ''}.")
390
+ for i in res.issues:
391
+ flag = " SUSPICIOUS" if i.suspicious else ""
392
+ print(f"\n {labels.get(i.kind, i.kind):20} {i.path} ({i.component}){flag}")
393
+ for pid in i.suspicious:
394
+ print(f" matches: {integ.describe(pid)}")
395
+ if res.verified:
396
+ print(f"\n verified against official checksums: {len(res.verified)} component(s)")
397
+ if res.unverified:
398
+ print(f" could not be verified: {len(res.unverified)} component(s)")
399
+ for u in res.unverified[:40]:
400
+ print(f" {u['component']}: {u['reason']}")
401
+ if not res.issues:
402
+ print("\n No modified or unexpected files in the components that could be verified.")
403
+ print("\n This compares files with wordpress.org checksums and looks for common backdoor code.\n"
404
+ " It is not a signature-based malware scanner.")
405
+ return 1 if res.tampered else 0
406
+
407
+
375
408
  def _report(args):
376
409
  rows = reportgen.load_rows(args.files)
377
410
  feed = FeedManager().current()
@@ -438,6 +471,14 @@ def main(argv=None):
438
471
  _report_args(wpc)
439
472
  wpc.set_defaults(func=_wordpress)
440
473
 
474
+ ig = sub.add_parser("integrity", help="check WordPress core and plugin files against wordpress.org "
475
+ "checksums; flag injected files and backdoor code")
476
+ ig.add_argument("path", help="path to the WordPress root")
477
+ ig.add_argument("--locale", default="en_US", help="WordPress locale of the install (default en_US)")
478
+ ig.add_argument("--no-plugins", action="store_true", help="check core and uploads only")
479
+ ig.add_argument("--json", action="store_true")
480
+ ig.set_defaults(func=_integrity)
481
+
441
482
  rp = sub.add_parser("report", help="aggregate JSON results into an HTML fleet dashboard")
442
483
  rp.add_argument("files", nargs="+", help="JSON files from scan/deps/wordpress --json")
443
484
  rp.add_argument("--out", help="write HTML to a file instead of stdout")