⌘K

Security

SynaptikCMS ships with a layered security setup out of the box. This page covers what is protected, how, and what you should configure before going to production.


Admin folder

During installation, install.php lets you choose a custom name for the admin folder. Use something non-obvious — avoid admin, cms, backend, or any other common name. This is the single most effective measure against automated scanners.


Protected paths

Sensitive paths are blocked at two levels: directory-level .htaccess files, and file-level rules in the root .htaccess.

Blocked files (root .htaccess)

PatternWhy
settings.jsonSite configuration — contains active theme, language, all site settings
admin-credentials.phpHashed admin password
.htaccess filesPrevent rule disclosure

Blocked directories (own .htaccess)

Each of these directories has its own .htaccess with Require all denied (Apache 2.4) and Deny from all (Apache 2.2 fallback):

PathContains
/data/All content JSON files (articles, pages, projects, categories, tags)
/bckps/Database backups and CSS editor backups
/private/Contact form CSRF secret and rate-limiting data

Security headers

Set via mod_headers in the root .htaccess:

HeaderValuePurpose
X-Frame-OptionsSAMEORIGINPrevents clickjacking — the site can only be framed by itself
X-Content-Type-OptionsnosniffBrowser must honour the declared Content-Type
Referrer-Policystrict-origin-when-cross-originLimits referer leakage to external domains
Permissions-Policycamera, mic, geo, payment all disabledDisables unused browser APIs
Content-Security-PolicySee belowControls which origins can load scripts, styles, fonts, frames

Default CSP

default-src 'self';
script-src  'self' 'unsafe-inline' https://js.hcaptcha.com https://cdn.jsdelivr.net;
frame-src   https://newassets.hcaptcha.com;
style-src   'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net;
font-src    'self' https://fonts.gstatic.com https://cdn.jsdelivr.net;
img-src     'self' data: blob:;
connect-src 'self' https://hcaptcha.com https://api.hcaptcha.com;
frame-ancestors 'self'

If you are not using hCaptcha, remove the js.hcaptcha.com, newassets.hcaptcha.com, hcaptcha.com, and api.hcaptcha.com entries. If you are not using Google Fonts, remove fonts.googleapis.com and fonts.gstatic.com.

ℹ️

'unsafe-inline' is required for scripts because the CMS injects inline JS for the i18n bridge (window.CMS_LANG) and gallery initialisation. Removing it will break the front end.


Contact form

The contact form (contact-process.php) has four independent protection layers:

LayerMechanism
CSRFHMAC-SHA256 token derived from a 32-byte secret stored in /private/contact.secret
HoneypotHidden field that bots fill in — submission is rejected silently
Rate limitingMax 5 submissions per IP per hour. IPs are stored hashed (SHA-256) in /private/contact_rate.json
hCaptchaOptional server-side verification. Configure via Settings → Contact

Theme preview token

The live theme preview uses a signed HMAC-SHA256 token with a 2-hour TTL. The secret is derived from the bcrypt hash of the stored admin password — no additional secret file is needed. The token only works when $_SESSION['admin'] === true.

See Live Theme Preview for full details.


Browser caching strategy

Assets are cached aggressively. The .htaccess sets:

Asset typeCache-ControlMax-age
CSS, JSpublic, immutable1 year
Images, fontspublic1 year
HTML, PHPno-storeNever cached

CSS and JS files served by render_header_scripts() include a ?v=<mtime> cache-busting parameter, so browsers automatically pick up changes without needing to clear cache.


Production checklist

[ ] Admin folder renamed to something non-obvious
[ ] /data/, /bckps/, /private/ return 403 (test: curl -I yourdomain.com/data/_index.json)
[ ] settings.json not accessible (curl -I yourdomain.com/settings.json should return 403)
[ ] HTTPS enabled — the CSP and session cookie are ineffective over HTTP
[ ] Directory listing disabled on the server (Options -Indexes or server config)
[ ] PHP error display off in production (display_errors = Off in php.ini)