BlogposterCMS was designed with multiple layers of security in mind. While no system is entirely foolproof, following these guidelines will help keep your installation safe.
-
Environment secrets – Never commit real secret values to version control. Copy
env.sampleto.envand provide strong random strings for all salts and tokens. -
HTTPS – When running in production, place the app behind HTTPS and set
APP_ENV=production(orNODE_ENV=production) to enable secure cookies and redirects. -
Rate limiting –
config/security.jssets limits for login attempts and meltdown API calls. Tune these usingLOGIN_LIMIT_MAXandAPI_RATE_LIMIT_MAXif needed. -
Weak credentials – Logins with passwords under 12 characters are only accepted from
localhostwhenALLOW_WEAK_CREDS=I_KNOW_THIS_IS_LOCAL. Production startup aborts if a user namedadminor a short password is detected. -
CSRF protection – Admin routes use CSRF tokens to prevent cross-site request forgery. Clients must include the token when authenticating or performing sensitive actions.
-
Module sandboxing – Optional modules run inside a minimal sandbox built with Node's
vmmodule. Onlypathandfscan be required and network access is blocked. Faulty or malicious modules are deactivated automatically when health checks fail. -
JWT event bus – All internal actions pass through the meltdown event bus. Each event carries a signed token and is validated before execution to prevent unauthorized operations.
-
HTTP security headers – Configure a Content-Security-Policy and other headers (using middleware such as
helmet) to protect against common attacks like XSS and clickjacking. -
Session management – Keep JWT secrets private and rotate them periodically. Tokens should expire after a reasonable time, especially for admin accounts.
-
Dependency audits – Run
npm auditregularly and update packages when security fixes are published. Review third‑party modules before enabling them. -
Database privileges – Create database users with only the permissions they need and restrict remote access where possible.
-
Monitoring and logs – Record login attempts and important actions. Reviewing logs helps detect suspicious behavior early.
-
Content sanitization – Design content is sanitised both when it is saved server-side and again when it is rendered in the browser. Public pages retain
<style>tags while stripping scripts and unsafe CSS patterns (likeexpressionor URLs usingjavascript:ordata:) so designs render without enabling script injection. -
Custom design scripts – Runtime rendering only executes design-supplied JavaScript when the payload carries an explicit trust flag (such as
allowCustomJs). Only literal booleantrue,1or the string equivalents'true','1','yes','y'or'on'are treated as trusted so stringified falsy values remain blocked. Restrict that capability to trusted authors via permissions or workflow reviews and audit designs regularly.
Always review your access logs and keep dependencies up to date. Security patches will continue to harden the platform over time.
The admin dashboard loads apps such as the designer inside an <iframe> and exchanges data via postMessage. To stop hostile pages from injecting commands, define the set of trusted parent origins in config/security.js or via the APP_FRAME_ALLOWED_ORIGINS environment variable. Multiple origins can be supplied as a comma-separated list (for example https://admin.example.com,https://staging-admin.example.com).
At startup the CMS now requires an RSA key pair for iframe origin tokens. Provide the PEM-encoded values through the environment:
APP_FRAME_ORIGIN_TOKEN_PRIVATE_KEY– PKCS#8 private keyAPP_FRAME_ORIGIN_TOKEN_PUBLIC_KEY– SPKI public key
Startup aborts if either value is missing so deployments cannot fall back to an insecure development key. A short-lived, signed token that encodes the allowed origins is delivered to the iframe via the query string, and the designer downloads the matching public key from /apps/designer/origin-public-key.json before verifying the signature with the WebCrypto API. Only when the signature, referrer origin, and postMessage source all match the configured whitelist will the iframe accept admin tokens.
Origins reported as null (from sandboxed or about:blank documents) or using non-HTTP(S) schemes remain blocked even if the origin token lists them.
For local development you can generate a key pair with:
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out origin-token-private.pem
openssl rsa -in origin-token-private.pem -pubout -out origin-token-public.pemPaste the PEM strings (with newline escapes) into your .env file before starting the server.
When APP_ENV=production (or NODE_ENV=production) is set, the admin_jwt cookie is marked as secure.
Browsers will only store this cookie over HTTPS connections. If you access the
admin interface using plain HTTP, the login page may simply reload without an
error because the cookie is ignored. Either use HTTPS (for example via a local
reverse proxy) or unset APP_ENV/NODE_ENV while testing locally.
When writing your own modules keep these best practices in mind:
- Validate and sanitize all user-supplied data before emitting events.
- Never trust payloads from other modules unless they include a valid JWT and the expected permissions.
- Avoid dynamic code execution (such as
eval) and keep your dependency list small. - Document the permissions your module requires in
moduleInfo.jsonso administrators understand the impact.
Following these rules helps protect the entire system as it grows.