diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..c9fb60d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,61 @@ +# Repository instructions + +Read [README.md](README.md) for setup and usage, +[CONTRIBUTING.md](CONTRIBUTING.md) before changing the project, and +[SECURITY.md](SECURITY.md) for security-reporting boundaries. + +## Project map + +- `wordpress_check.py`: single-file, standard-library-only Python 3.10+ CLI, + passive fetcher, PHP2Shell classifier, and CSV/JSON/HTML report rendering. +- `test_wordpress_check.py` and `test_php2shell.py`: local HTTP fixtures and mocks. +- `docs/REFERENCE.md`: command options, output fields, and request behavior. +- `docs/PHP2SHELL.md`: source-linked classification rules and limitations. +- `skills/php2shell-check/SKILL.md`: reusable instructions for agents using the + checker; `agents/openai.yaml` inside that skill provides discovery metadata. +- `CLAUDE.md`: points Claude to these shared instructions; keep policy here. + +## Implementation constraints + +Keep the checker usable as one Python file with no third-party runtime or test +dependencies. Preserve public-page-only requests, verified TLS, robots checks, +the descriptive User-Agent, pacing, response-size limits, and bounded redirects. +Do not add exploit probes, authentication bypasses, or automatic retries around +access restrictions. Running tests or editing this repository does not authorize +scanning real websites. + +Advertised versions are evidence, not verified runtime state. Keep missing, +conflicting, prerelease, vendor-qualified, and uncovered-branch cases uncertain. +Never turn `fixed_version_reported` into a guarantee of safety or +`potentially_affected` into confirmed exploitability. Preserve +`php2shell_exploitability=not_tested` and the distinction between fetch, +WordPress-detection, and PHP2Shell results. + +Change the embedded fix table or rule date only after checking the official +advisories. Add branch-boundary and vendor-qualification tests with such changes. +Keep CLI/output changes aligned with the reference, README, and agent skill. +For the skill, use the real CLI rather than a second scanner implementation; +keep it usable after installation outside this checkout. + +## Validation and delivery + +Run from the repository root: + +```sh +python -m unittest -v +python wordpress_check.py --help +git diff --check +``` + +The suite uses mocks and ephemeral local HTTP servers; it must not contact +external websites. Add focused tests for behavior changes. For documentation +or skill edits, check commands against `--help` and source, verify referenced +paths, and validate skill frontmatter/UI metadata with the skill tooling when +available. Do not add tests that only assert prose wording. + +Use focused branches and pull requests linked to their issues. Preserve unrelated +work. Keep real target lists, reports, workbooks, credentials, and private contact +data out of commits. Verify CI for the actual PR head, resolve review findings, +and merge only when authorized. Report local checks, hosted CI, and any live +observations separately. Follow [LICENSING.md](LICENSING.md) and +[BRAND_ASSETS.md](BRAND_ASSETS.md) when distributing code or branded reports. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..32eb664 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,6 @@ +# Claude instructions + +Read and follow [AGENTS.md](AGENTS.md) before working in this repository. It is +the shared source of repository instructions and validation requirements. + +Read [README.md](README.md) for project setup, usage, and the agent skill. diff --git a/README.md b/README.md index 27aabcb..645b3d9 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,35 @@ Thresholds come from the PHP project's advisories for [CVE-2026-109618](https:// Check only websites you are authorized to assess, and keep real target lists and results out of version control. +## Agent skill + +The [php2shell-check skill](skills/php2shell-check/SKILL.md) guides an agent +through authorized passive checks, report creation, interpretation of uncertain +results, and preservation of interrupted runs. It uses the existing CLI and +contains no separate scanner or runtime dependencies. + +Copy the entire `skills/php2shell-check/` directory into your agent's skill +directory, keeping `SKILL.md` and `agents/openai.yaml` together. For Codex, use +`$CODEX_HOME/skills/php2shell-check/` (normally +`~/.codex/skills/php2shell-check/`) for a personal installation, or +`.agents/skills/php2shell-check/` in the project where you want to use it. +Check for an existing installation before copying so local edits are preserved. +Reload the agent session if needed to discover the skill. + +The skill can be installed independently, but running checks still requires +Python 3.10+ and a checkout of this repository or its `wordpress_check.py` file. +It explains how to locate or obtain the checker; do not assume it lives beside +the installed skill. Then ask, for example: + +```text +Use $php2shell-check with my local checker checkout to assess the authorized +websites in /path/to/authorized-sites.txt. Save JSON to a new file outside the +repository, summarize the evidence and unknown results, and report the rule date. +``` + +For agents contributing to this repository, [AGENTS.md](AGENTS.md) contains the +shared development instructions; [CLAUDE.md](CLAUDE.md) points Claude to them. + ## Documentation - [Full reference](docs/REFERENCE.md): every CLI option, output field, and request rule diff --git a/skills/php2shell-check/SKILL.md b/skills/php2shell-check/SKILL.md new file mode 100644 index 0000000..0387459 --- /dev/null +++ b/skills/php2shell-check/SKILL.md @@ -0,0 +1,147 @@ +--- +name: php2shell-check +description: Use php2shell-check for passive PHP2Shell exposure triage of authorized websites, interpret advertised PHP versions and WordPress markers, and produce CSV, JSON, or HTML reports. Use for running or interpreting this checker, not exploit testing or server patching. +--- + +# PHP2Shell Check + +Use the dependency-free `wordpress_check.py` CLI from +[CompleteTech-LLC/php2shell-check](https://github.com/CompleteTech-LLC/php2shell-check). +It compares advertised PHP versions with an embedded, dated rule snapshot; +it does not establish exploitability. WordPress is not required for the check. + +## Locate the checker + +This skill contains instructions, not a bundled copy of the scanner. Use the +user's existing checkout or standalone `wordpress_check.py` when available. +Otherwise clone the repository into a new local directory: + +```sh +git clone https://github.com/CompleteTech-LLC/php2shell-check.git +cd php2shell-check +python --version +python wordpress_check.py --help +``` + +Python 3.10+ is required; substitute `python3` where appropriate. No pip package, +API key, or browser is needed. Run the examples from the checker directory, or +use its absolute script path. Do not assume an installed skill's parent directory +contains the checker. Record the checkout revision when available and retain +`php2shell_rules_as_of` and `php2shell_sources` from the results. The rule table +does not refresh automatically. + +For additional options, use the checkout's `--help` and `docs/REFERENCE.md`; +for classification details, read `docs/PHP2SHELL.md`. If only the standalone +script is available, consult the same files in the upstream repository at the +matching revision when known. + +## Select scope and inputs + +- Use only targets covered by the user's authorized assessment. Reuse clear + existing authorization; ask only if scope or permission is genuinely missing. + A permissive or missing robots.txt is not authorization. +- The checker fetches robots.txt and the supplied page, following up to five + page redirects and checking destination robots policies. It can follow + redirects to other hosts and accepts local/private addresses; it has no host + allowlist option. If a strict host boundary is required, use an appropriately + restricted network environment or offline evidence instead of assuming the + CLI enforces that boundary. +- Pass explicit HTTP(S) URLs or bare domains (which default to HTTPS). For a + batch, prepare UTF-8 text with one target per line. Blank lines and full-line + `#` comments are ignored; a BOM is accepted. Exact duplicates are skipped. + `--input` does not read CSV or Excel: extract only the authorized URL column + into a separate text file first. Do not include credentials or secret tokens. +- Keep the existing TLS checks, honest User-Agent, robots rules, and sequential + pacing. Do not bypass restrictions, probe guessed admin/PHP-info endpoints, + send exploit payloads, or add retries to get around a block. + +## Run and preserve the output + +Choose a new output path outside version control; create its parent directory +first. `--output` overwrites an existing file. The following paths and domains +are examples: replace them with the authorized inputs and chosen output paths, +and do not scan example domains as a test. + +```sh +# One target; JSON retains structured evidence and notes. +python wordpress_check.py https://example.com --format json --output ../assessment.json + +# Authorized text list; keep progress on stderr and results in a file. +python wordpress_check.py --input ../authorized-sites.txt --format csv --output ../assessment.csv --delay 2 --timeout 15 + +# Shareable offline report, with optional authorized branding. +python wordpress_check.py --input ../authorized-sites.txt --format html --output ../assessment.html --brand "Your Organization" --logo ../logo.png +``` + +Choose the requested format rather than rerunning every target for each example. +CSV is the default, and omitting `--output` sends results to stdout. JSON retains +arrays; CSV joins arrays with ` | ` and guards spreadsheet-formula strings. +HTML is a self-contained summary report. Use JSON or CSV when full per-target +evidence and timestamps must be preserved; HTML does not expose every field. +`--brand` and `--logo` affect HTML only; a missing logo file is omitted. + +`--delay` and `--timeout` must be positive finite numbers. Delay defaults to one +second per origin and can be increased by robots rules. Timeout defaults to 15 +seconds **per socket**, not a total run deadline. Add `--contact` only for a +public contact value the user intends to disclose in requests. + +Inspect each result even if the process exits with `0`: that means the run +completed, not that every fetch succeeded or every site is patched. Argument or +input-file errors exit with `2`; unexpected I/O errors can raise exceptions. +For blocked or failed targets, report the reason without silently retrying. + +On interruption, preserve the output before any rerun. Completed CSV rows are +flushed incrementally; JSON may lack its closing bracket. HTML is rendered from +completed rows during normal finalization, including a handled interruption +path, but a force-killed process may leave it empty. There is no automatic +resume. Determine which targets completed, then run only authorized outstanding +targets into a **new** output file if continuation is requested or already in +scope; do not imply the original run completed. + +## Interpret and deliver + +| `php2shell_status` | Report this meaning | +| --- | --- | +| `potentially_affected` | An unqualified advertised release is below its branch's upstream fix. Prioritize administrator verification of the actual package and runtime. | +| `fixed_version_reported` | The advertised release meets the embedded branch threshold. This does not verify deployed patch state or certify safety. | +| `unknown` | Evidence cannot support a classification: missing, partial, conflicting, prerelease, vendor-qualified, or outside the covered branches. Preserve the stated reason. | + +Read `php2shell_version_status`, `php2shell_notes`, `php2shell_fixed_version`, +and `php2shell_recommendation` alongside the classification. Preserve build +qualifiers: vendors can backport fixes to older base versions. All results have +`php2shell_exploitability=not_tested`; do not infer a PHP SAPI or RCE from a server +header. Do not replace the embedded thresholds with recalled version numbers. +If current patch advice is requested, verify the official sources and clearly +distinguish that advice from the tool's recorded snapshot. + +Keep detection `status` and `fetch_status` separate from `php2shell_status`. +`no_evidence` does not prove WordPress is absent; asset `?ver=` hints are not +confirmed WordPress versions. Coarse `fetch_status=blocked` can include HTTP, +TLS, or invalid-input errors; read `status`, `http_status`, and `notes` for the +reason rather than claiming the owner deliberately blocked the check. + +Deliver the report path, completed/failed target counts, classification counts, +rule date, and key limitations. Include final URL, observed PHP evidence, and +check timestamp for findings when available. Label any incomplete run. Keep +real target lists and results out of commits; writing a report does not authorize +publishing it, contacting site owners, or changing a server. + +## Offline verification + +For development or a smoke check, use the repository's local-only suite: + +```sh +python -m unittest -v +python wordpress_check.py --help +``` + +To classify an already supplied version without contacting a website, run from +the checker directory and preserve any vendor suffix: + +```sh +python -c "import json; from wordpress_check import assess_php2shell; print(json.dumps(assess_php2shell('8.3.6-0ubuntu0.24.04.13'), indent=2))" +``` + +Label this as offline version interpretation, not a live observation. For +conflicting supplied values, pass all values through `version_candidates` +instead of selecting one; do not invent a version when none was disclosed. diff --git a/skills/php2shell-check/agents/openai.yaml b/skills/php2shell-check/agents/openai.yaml new file mode 100644 index 0000000..788957b --- /dev/null +++ b/skills/php2shell-check/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "PHP2Shell Check" + short_description: "Run passive PHP exposure checks and interpret reports" + default_prompt: "Use $php2shell-check to assess my authorized website list and save a report that preserves uncertainty."