=== BoringSec Security ===
Contributors: boringsec
Tags: security, scanner, audit, monitoring, vulnerability
Requires at least: 6.3
Tested up to: 7.0
Requires PHP: 7.4
Stable tag: 1.3.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Get a privacy-safe local WordPress security baseline before connecting, then add public intelligence and owner-gated integrity scanning.

== Description ==

BoringSec Security connects one WordPress installation to one BoringSec domain.

The plugin is designed around a clear security boundary:

* A local baseline is visible before connection and makes no external request.
* After approval, the complete privacy-safe baseline and lightweight report are available before domain verification.
* Seven heavy scanners — bounded WordPress filesystem integrity, Injection, XSS, Ports, Nuclei, OWASP ZAP, and Medusa — are enabled only after this installation proves control through a signed, one-time challenge.
* Connecting never creates a subscription or charge.
* Optional BoringSec protection plans add recurring monitoring and are purchased on BoringSec's hosted billing page.
* The BoringSec access token and verification secret are encrypted locally using WordPress salts.
* Connection credentials expire within 30 days and are automatically rotated shortly before expiry.
* The credential can scan and read reports only for the exact canonical connected site URL, including its host and path.
* A complete installation-progress view, operational diagnostics, contextual Help tabs, privacy controls, and safe remediation guidance stay visible in WordPress.
* After connection, a bounded essential heartbeat reports plugin/runtime versions and allowlisted readiness states so failed installations can be supported.
* Optional product-usage analytics are off by default and contain only allowlisted action names, random event IDs, and timestamps when enabled.
* Connected sites use a fail-closed stable release channel that verifies package origin, size, and SHA-256 before WordPress installs an update.

The plugin makes no external request on activation or while generating the local baseline. An administrator must explicitly click “Connect and enrich my report.”

= External services =

This plugin connects to the BoringSec SaaS service at `https://www.boringsec.com` only after explicit administrator action. It sends the site URL and name, WordPress/PHP/database/plugin versions, component slugs and versions, aggregate role counts, configuration booleans, file-permission summaries, installation-keyed runtime-error fingerprints, an installation identifier, connection proof, and requested audit operations. It never sends usernames, email addresses, WordPress salts, credentials, error messages, file contents, or absolute paths. After domain verification, the bounded integrity scanner sends only relative paths and SHA-256 hashes for missing, modified, unexpected, or suspicious files, plus coverage counters and error codes. It receives connection state, security findings, scores, report links, and subscription/monitoring state.

After connection, an essential operational heartbeat sends schema version 1; plugin, WordPress, and PHP versions; site locale and environment class; multisite, automatic-update, and optional-analytics booleans; and allowlisted cron, outbound HTTP, REST, baseline, lightweight-scan, integrity, and secure-updater statuses. It may include only a bounded uppercase error code with its timestamp. It never includes usernames, emails, credentials, secrets, raw errors, configuration values, absolute paths, or file contents. This heartbeat is required to operate and support a connected installation. WP-Cron checks hourly, unchanged recurring state is limited to once per six hours, and queued changes or bounded retries may run sooner.

Optional product-usage analytics are disabled by default. If a WordPress administrator enables them, the plugin may send only an allowlisted action name, a random event ID, its timestamp, and the bounded plugin version at the time of that action. Events are captured only for the exact active connection generation and are cleared rather than attributed to a later connection. The local event queue is bounded, expires after seven days, retries through the connected heartbeat, and is deleted immediately when optional analytics are disabled. The preference can be changed before connection without making a network request.

Service terms: https://www.boringsec.com/terms

Privacy policy: https://www.boringsec.com/privacy

After connection, the secure updater may request the public stable-release manifest from `https://www.boringsec.com/api/integrations/wordpress/releases` and download the exact versioned release archive from `https://www.boringsec.com/downloads/wordpress/`. Beyond normal HTTPS transport metadata and the source IP visible to BoringSec, these requests carry only standard content-negotiation headers and a privacy-safe updater user agent containing the installed plugin version; they do not send the site URL, installation or connection identifier, credentials, users, or scan data. WordPress receives an update only for a newer stable semantic version, and the archive's exact byte size and SHA-256 checksum are verified before installation. Redirects are rejected, and the plugin never forces automatic installation.

After connection, lightweight WordPress Site Health checks may contact the official WordPress.org API at `https://api.wordpress.org` to confirm update-service reachability and compatibility. After domain verification only, integrity checks request official core checksum metadata from `https://api.wordpress.org`, plus official plugin checksum metadata and theme packages from `https://downloads.wordpress.org`. These requests contain only the installed WordPress locale/version or WordPress.org component slug/version needed to select the official reference; BoringSec credentials, site user data, file contents, and local paths are never sent to WordPress.org. Downloaded theme references are bounded, validated without extraction, compared locally, and deleted. These requests run only during an administrator-approved connected baseline or a verified-domain integrity scan.

WordPress.org privacy policy: https://wordpress.org/about/privacy/

WordPress.org terms: https://wordpress.org/about/terms/

== Installation ==

1. Upload the `boringsec-security` directory to `/wp-content/plugins/`, or install the ZIP through Plugins → Add New → Upload Plugin.
2. Activate BoringSec Security.
3. Open BoringSec in the WordPress admin menu.
4. Review the local baseline and data disclosure, then click “Connect and enrich my report.”
5. Sign in to BoringSec, verify the exact site shown, and approve it.
6. Return to WordPress. The plugin securely claims its one-time credential, uploads the signed baseline, and queues the lightweight audit.
7. Review the completed lightweight report, then explicitly click “Verify ownership” to unlock only the seven heavy scanners: WordPress filesystem integrity, Injection, XSS, Ports, Nuclei, OWASP ZAP, and Medusa.

The site must use HTTPS and allow BoringSec to reach the public WordPress REST verification endpoint.

== Frequently Asked Questions ==

= Does activation send site data to BoringSec? =

No. The local baseline uses existing WordPress state and update transients only. External requests begin only after an administrator explicitly clicks Connect.

= Do I need to verify the domain before seeing a report? =

No. The plugin shows local hardening findings before connection. After connection, BoringSec exposes the maximum safe lightweight findings before verification. Only the seven heavy scanners, including WordPress filesystem integrity, require ownership proof.

= Does connecting create a paid subscription? =

No. A subscription is created only through an explicit BoringSec checkout flow using server-controlled pricing.

= Does the plugin send usage analytics? =

Optional product-usage analytics are off by default. If you enable them in the BoringSec admin screen, only allowlisted action names, random event IDs, timestamps, and the bounded plugin version at occurrence are sent after connection. Disabling the preference removes the pending local event queue immediately. The essential connected-service heartbeat is separate and is disclosed in the admin privacy table.

= How are plugin updates delivered? =

Only an actively connected installation checks BoringSec's public stable release manifest. WordPress is offered only a newer stable semantic version from the exact allowed release origins. The updater validates the declared package size and SHA-256 checksum before installation and fails closed with a safe Site Health remediation if any check differs. Automatic installation remains controlled by the WordPress administrator.

= Where are credentials stored? =

The one-time device code, access token, and verification secret are encrypted before storage in WordPress options. BoringSec issues a narrowly scoped credential bound to the exact canonical connected site URL (host and path), limited to 30 days, and automatically rotated during its final seven days.

= What happens when I disconnect? =

The plugin first asks BoringSec to revoke the credential, then removes local connection data and scheduled synchronization. If the server cannot be reached, it retains only the encrypted credential needed to retry revocation, disables scanning, and offers a separate explicit local-only clear action. The 30-day server expiry is the final fail-safe.

= What does the local integrity scanner read? =

Only after ownership verification, it compares official WordPress core and plugin checksums, validates official theme packages without extraction, and searches fixed core/uploads roots for unexpected executable files, PHP in uploads, and high-confidence code signatures. Official component references are used only when WordPress update metadata or an exact official component URL proves provenance; custom or ambiguous components are reported as ineligible rather than compared to a colliding WordPress.org slug. It skips symlinks and special files, enforces file/byte/time/network/package limits, and sends no file contents or absolute paths. A safety limit produces an explicit partial result rather than a false clean result. Each integrity manifest echoes the server-signed snapshot ID and canonical fingerprint of the exact accepted baseline it scanned. Signed outbox payloads are stored durably and replayed byte-for-byte after lost responses or credential rotation. The upload is synchronously merged into the exact connected WordPress report; it does not consume another generic lightweight scan. If the baseline changed during an integrity pass, BoringSec refreshes baseline and vulnerability findings, rejects the stale integrity evidence, and schedules a new bounded pass. Injection, XSS, and Ports run in process; Nuclei, OWASP ZAP, and Medusa run in isolated BoringSec infrastructure.

== Privacy ==

The plugin provides suggested privacy-policy text under Settings → Privacy and an exact stage-by-stage disclosure in the BoringSec admin screen. Runtime diagnostics are stored only as installation-keyed fingerprints with daily aggregate counts for a rolling 30-day window; raw messages and paths are never stored. Optional usage events are bounded and expire locally after seven days. Local connection, posture, runtime-fingerprint, telemetry preference/queue/runtime, updater state/cache, outbox, and scanner-state data is removed when the plugin is uninstalled. Uninstall makes a bounded best-effort revocation attempt before local removal; disconnect keeps a retry path if immediate revocation fails.

== Changelog ==

= 1.3.0 =

* Added a complete installation and protection progress view with explicit prerequisites for connection, baseline, lightweight report, ownership verification, and all seven heavy scanners including filesystem integrity.
* Added transparent operational diagnostics for versions, REST/outbound/cron readiness, credential expiry, signed outbox state, scheduled jobs, automatic updates, and secure release checks.
* Added contextual WordPress Help tabs, in-panel setup guidance, privacy tables, safe error codes, and deterministic remediation links.
* Added a bounded essential connected-service heartbeat for installation/version/operational support, with strict schema allowlists and no raw site content or identities.
* Added optional allowlisted usage analytics that are off by default, locally bounded, expiring, retryable, and immediately cleared on opt-out.
* Added fail-closed stable plugin updates with fixed origins, strict release metadata, redirect controls, exact size checks, SHA-256 verification, Site Health diagnostics, and no pre-connection updater request.
* Preserved complete lightweight findings before ownership verification; only the seven heavy scanners, including filesystem integrity, remain owner-gated.

= 1.2.0 =

* Added the v2 WordPress posture contract with scoped local and connected Site Health coverage.
* Added bounded WordPress.org plugin checksum and theme package integrity verification.
* Added explicit modified, missing, and unexpected component-file findings with honest ineligible coverage.
* Added rolling privacy-safe WordPress compatibility diagnostics and expanded pre-authorization local findings.
* Added encrypted one-time device codes, 30-day credential enforcement, automatic rotation, revocation retry, and multisite-safe uninstall cleanup.
* Added migration-safe rotation of still-valid legacy credentials that were issued with the previous longer lifetime.
* Replaced the post-integrity generic scan with a server-confirmed synchronous merge into the exact connected WordPress report.
* Added exact WordPress.org component provenance and race-safe baseline/integrity report refresh handling.

= 1.1.0 =

* Added a no-network local WordPress baseline before connection.
* Added signed, replay-resistant baseline and integrity posture uploads.
* Added privacy-safe component, hardening, role-count, permission, Site Health, and aggregate fatal-error posture.
* Added verified-only, bounded core checksum and uploads integrity scanning with honest partial coverage.
* Reordered first-run flow so baseline upload and lightweight scanning occur before explicit domain verification.
* Preserved opaque credentials byte-for-byte after strict validation.

= 1.0.0 =

* Initial release.
* Explicit device authorization and exact canonical site-URL binding.
* Lightweight pre-verification reports and owner-gated heavy scanners.
* Encrypted local credentials, rotation, revocation, status sync, Site Health, and dashboard integration.
