2 Commits

Author SHA1 Message Date
peptiderepo
fff3fce432 v1.5.2: CF-peer validated client IP, grandfather migration, de-short-circuit register
Security follow-up to v1.5.1. Closes four items from the v1.5.1 review —
two ship-blockers and two mediums — all within the ADR-0001 envelope.

PSEC-007 — peptide_starter_get_client_ip() now trusts CF-Connecting-IP
only when REMOTE_ADDR falls inside a published Cloudflare edge range.
Previously, any direct-to-origin request (which Hostinger permits) could
forge its rate-limit key by setting the header to a different IP per
attempt, bypassing every abuse control in the theme. New module
inc/cloudflare-ips.php embeds a dated snapshot of CF v4/v6 ranges and a
CIDR matcher covering both families; list is overridable via the
peptide_starter_cloudflare_ip_ranges filter for out-of-band updates.
HTTP_X_FORWARDED_FOR stays ignored unless operators opt in via the
peptide_starter_trust_xff filter.

PSEC-008 — Removed the v1.5.1 user-verification migration (Option A as
confirmed by peptiderepo). The sync-wp_mail-per-subscriber loop on
admin_init would have blocked wp-admin and hammered deliverability.
Existing accounts are now grandfathered: no ps_pending_verification
meta = verified. Verification applies only to registrations from v1.5.2
forward. The ps_verify_migration_version option (written by v1.5.1) is
cleared on theme activation.

PSEC-009 — Registration validation no longer short-circuits. All five
checks (username pattern, email validity, password length,
username_exists, email_exists) evaluate unconditionally before the
combined rejection. Closes the response-time oracle that let an
attacker distinguish microsecond-fast regex rejection from DB-round-trip
rejection and infer which field triggered the failure.

PSEC-010 — Added the happy-path verify test that v1.5.1 was missing.
Covers token match, user meta cleanup, auth cookie set, and the
peptide_starter_user_verified action firing with the correct user ID.

Seven new rate-limiter tests confirm CF-peer validation works
end-to-end: trusted CF peer honours the header, untrusted peer ignores
spoofed headers, invalid values fall through, XFF default-off, XFF
filter opt-in, CF range filter override, IPv6 CIDR match, family
mismatch rejection.

Confirmed with peptiderepo before coding: (1) Option A for PSEC-008
because zero users; (2) Cloudflare IS in front of the origin (dig
confirms 104.21.x / 172.67.x + CF-Ray response header), so PSEC-007 is
a real fix not dead code; (3) no staging — treat prod as staging.

ARCHITECTURE.md gains a client-IP trust model section; CONVENTIONS.md
documents the header-trust rules for future modules.

Version bumped to 1.5.2 in style.css and functions.php.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 15:39:09 +07:00
peptiderepo
cb8b73f4ab v1.5.1: frontend auth hardening — rate limiting, email verification, honeypots, CSV safety
Security-only release per ADR-0001. Closes all six ship-blockers from the
post-v1.5.0 audit: PSEC-001 (no rate limiting), PSEC-002 (account
enumeration via separate error messages), PSEC-003 (registration auto-login
with no email verification), PSEC-004 (ungated "My Data" templates),
PSEC-005 (CSV formula injection on subscriber export), PSEC-006 (no
honeypot/CAPTCHA on public forms).

Adds inc/config.php (single source of truth for all security thresholds,
filterable via peptide_starter_security_config), inc/rate-limiter.php
(Peptide_Starter_Rate_Limiter + Cloudflare-aware client IP resolver,
transient-backed, never stores raw IPs), and inc/email-verification.php
(43-char token, 24h TTL, /verify rewrite, rate-limited resend endpoint).

Auth handlers rewritten to: unify all failure messages, rate-limit before
any expensive check, drop registrations with a filled honeypot silently,
stop auto-login on register, send a verification email instead. The
require_login() helper lives in inc/helpers.php and is applied at the top
of page-tracker.php, page-subject-log.php, and page-protocol-builder.php;
page-calculator.php stays open (no PII, no writes).

Newsletter signup gains: consent checkbox, privacy link, honeypot,
autoload=false on the wp_options blob, unsubscribe token stored per row,
/newsletter-unsubscribe route, merged success+duplicate into a single "ok"
state. Admin export runs every cell through peptide_starter_csv_safe()
which prefixes leading =/+/-/@/tab/CR with a quote.

Contact handler hardens against email-header injection (rejects name
values with \r \n , < >), rate-limits, honors honeypot, tags mail
failures with a request ID for correlation without logging message
content.

Adds Tools → Mail Test (inc/mail-diagnostic.php): a permanent wp_mail
probe so we can check Hostinger outbound deliverability any time it looks
flaky. Adds a one-time admin_init migration that enrols pre-v1.5.1
subscribers into the verification flow (currently a no-op — zero users —
but guarded for the future).

Other cleanup from the audit: fallback primary menu moved out of
header.php into inc/helpers.php (redeclaration risk), placeholder footer
language links replaced with "Translations coming soon", footer copyright
now reads through the customizer getter, settings-panel gains a proper
Tab/Shift+Tab focus trap and saves/restores body overflow, documentation
heading IDs slugified from heading text with collision counters, JS files
standardized on const/let.

Six new PHPUnit suites cover rate limiter lifecycle, auth handler error
unification and rate limits, email verification token generation and
expiry, contact handler header injection + rate limit + honeypot,
newsletter signup consent + CSV safety, and require_login gate behavior.

ARCHITECTURE.md and CONVENTIONS.md updated in the same commit — new
module layout, data flows, security patterns for rate-limiting,
honeypotting, gating, and CSV-safe export.

Version bumped to 1.5.1 in style.css and functions.php.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 13:01:22 +07:00