Panel CommentsAdmin sign in
Documentation

Security

Security model

Browser boundary

Websites are selected only from an exact normalized browser Origin header. The administration UI calls this a Website address. Wildcards and referer-based trust are not used. API responses allow only the configured exact address and never use credentialed CORS.

Posting requires a signed website-bound visitor credential. Each write consumes a short-lived form ticket tied to website, visitor, page, and action. Forms include a ticket-specific randomized honeypot. The widget also writes a signed, website/origin/visitor-bound proof to a first-party cookie and reads it back before requesting a comment form. An administrator can require this round trip, send failures to moderation, or disable it. The proof contains no personal information and is defense in depth rather than a claim that cookies cannot be automated.

Reaction writes use the same visitor credential, signed cookie round trip, one-use action/page-bound ticket, optional Turnstile verification, and actor/IP/target rate limits as other browser writes. The database stores keyed actor and network-prefix signals rather than a raw IP address. Claimed-only mode binds reactions to a reserved commenter identity; guest mode remains one reaction of each type per signed browser profile and target. Aggregate-only reactions imported from another platform have no fabricated actor record.

Minimum form age, visitor/IP/website token buckets, content fingerprints, link heuristics, moderation rules, administrator-authored banned words/phrases, URL/domain rules, and IPv4/IPv6 or CIDR rules work without external services. Matches can be stored as spam, held for moderation, or silently discarded.

Remote blocklists are opt-in per website. Built-in sources include Stop Forum Spam, NEBLINK, Spamhaus DROP, DShield, and Feodo Tracker; administrators can add custom HTTPS IP/CIDR and domain lists. Custom domain lists and the direct banned-domain setting accept anchored * patterns such as example*.com, *example.com, and *example*.*. Panel Comments downloads guarded copies into panel-content/blocklists/ and performs all matching locally. Comment bodies, email addresses, and visitor IP addresses are never sent to blocklist providers. The fetcher rejects non-HTTPS URLs, credentials, nonstandard ports, redirects, and private/reserved destinations, pins DNS resolution, limits downloads, and retains stale usable data when an update fails. Each website has a configurable one-hour-to-seven-day refresh interval that is honored by both the built-in web runner and optional cron worker. IP reputation lists can contain shared, reassigned, proxy, or VPN addresses, so no source is enabled by default.

Turnstile is optional per website. When enabled, keys are stored per website, the secret is encrypted, and verification checks hostname, action, cData, remote address, and idempotency. Adaptive and every-submission policies are available.

Commenter identity and conversation integrity

Reserved handles are unique inside one configured website; ordinary display names are intentionally not unique. Password-based profiles use Argon2id and one-use Argon2id recovery codes. Email-based profiles use short-lived one-use links and encrypted email storage. Password-only profile creation is bound to the signed browser profile rather than enforcing a one-account-per-IP rule.

Canonical guest-name mode keeps one display name per signed browser profile. Renaming a guest or claimed profile updates all linked non-deleted comments. Public website- or discussion-scoped guest labels help readers distinguish otherwise identical display names without exposing internal browser IDs.

Posting records correlation reasons when a browser changes identities or stages a direct reply under another identity. Same-browser evidence is high confidence and can be flagged, held, or blocked. A rapid direct reply sharing only an IP hash is recorded as weaker network evidence; shared IP addresses alone do not prove a shared person. Private browser identifiers, keyed signup-network matches, and expiring submission-network hashes are visible only to authorized moderators.

Stored data

panel-config.php and files under panel-content/ are executable PHP guards. Direct requests return an empty 404 before configuration, master-key, cache, log, lock, or protected-backup bytes can be reached. This protection works under stock Nginx and does not depend on .htaccess.

Gravatar is disabled by default. When a website owner enables it, Panel Comments normalizes the private comment email and sends only its SHA-256 identifier to Gravatar from the server. Cached image files retain the executable 404 guard, readers receive a local comment-ID URL instead of the email hash, and reader IP addresses and referrers are never sent to Gravatar.

XChaCha20-Poly1305 protects email addresses, Turnstile secrets, webhook secrets, and TOTP seeds. Administrator passwords and recovery codes use Argon2id. Commenter IP addresses are never stored; keyed hashes expire with submission facts. Administrator-authored banned IP/CIDR rules remain in website configuration by design.

Rendered comments pass through CommonMark with raw HTML disabled and then an allowlist sanitizer. The widget applies another DOM allowlist. Administration uses CSRF tokens, restrictive CSP/no-store headers, path-scoped SameSite/HttpOnly/Secure sessions, role checks, rate-limited login, optional TOTP, and moderation audit records.

Public manuals are limited to a fixed documentation catalog, use the same raw-HTML-disabled renderer with safe relative links, and cannot read arbitrary filesystem paths. Their HTML is served with a script-free CSP and short public caching. The public integration manifest contains only the product version, detected base URL, generic capabilities, supported snippets, and public endpoint URLs; it never queries or exposes website records, administrator data, configuration, health details, or secrets.

Webhook delivery allows HTTPS only, rejects credentials/private destinations, pins resolved public addresses, disables redirects, and signs each body. Operators should still keep PHP/MySQL current, use HTTPS, enable owner TOTP, test encrypted backups, and retain off-host backup copies.