Skip to content

Security model

phpRS edited this page Sep 21, 2026 · 1 revision

A content management system is as secure as the speed at which a fix reaches the sites. phpRS therefore focuses on two things: the fix arrives by itself, and nobody else can arrive in its place.

For the practical checklist after installation see the manual page Security.

Reporting a vulnerability

Please do not report security vulnerabilities publicly in Issues. Use private reporting on GitHub: Security → Report a vulnerability, or the e-mail address on phprs.eu. Include the version, steps to reproduce and the impact.

  • We reply within 3 working days.
  • A fix usually comes out within 14 days, critical ones as soon as possible.
  • After the release we publish a GitHub Security Advisory with thanks to the reporter.
  • Only the latest released version is supported.

How a fix reaches the sites

  1. The fix is released as a version flagged security.
  2. Every installation checks for news twice a day. With automatic updates on (the default), it installs a security release by itself within 12 hours – after a database backup and verification of the checksum and the publisher's signature.
  3. The administrator gets an e-mail and a notice in the administration. If the server cannot update itself (no zip/sodium, files not writable), the e-mail still arrives and the update is one button.

Signed updates

  • Ed25519 signature covers the version, the package checksum and the security flag – nobody along the way can turn an ordinary release into one that installs itself.
  • The private key never leaves the publisher's computer. Packages are built and signed locally; CI only creates a draft release. Compromising phprs.eu or GitHub is not enough to forge an update.
  • Backup key. Installations know two public keys (system/aktualizace.pub); the second is kept offline and allows a safe key rotation.
  • Integrity check. Every release carries a signed list of core files; System status reports changed, missing and added files.

Secure by default

  • Prepared statements everywhere, password_hash, CSRF tokens on every administration action, escaped output.
  • Two-factor sign-in with TOTP and backup codes, plus passkeys (fingerprint, Face ID) as a convenient second step. System status points out administrators without it.
  • Temporary account lock and per-IP limits against password guessing – for the newsroom and for readers.
  • Content Security Policy in the administration: no inline and no third-party scripts; HSTS and no-store.
  • Uploaded images are re-encoded; PHP does not run in media/; system/, storage/, tools/ and docs/ are not reachable from the web.
  • Outgoing requests (link checker, WordPress image import, Web Push) are protected against SSRF.
  • No third-party plug-ins and no third-party libraries at runtime – the most common way a CMS gets compromised does not exist here.
  • Boundaries for AI: the Claude (MCP) connection works only with content and custom templates; template PHP must pass an allow-list check. No access to code, users or the server. See Claude connection.

Continuous checks

Every change runs a smoke test (clean install + walk through the site and the administration) on PHP 8.4 and 8.5, Semgrep and Gitleaks. A daily workflow additionally verifies the signature of the update channel and the security headers of the website and the demo, and opens an issue if something fails.

Clone this wiki locally