Security

How Luster Protects You

Security was one of the primary reasons Luster was built. This page explains what Luster does to keep your site and your members' data safe.

Authentication

Passwords

What Luster Does

Luster hashes every password with Argon2id, a modern algorithm designed to be expensive for attackers to crack. No passwords are ever stored in plain text.

If you migrate from Enthusiast, Luster detects the old MD5 password hashes automatically. The next time a member logs in with the correct password, Luster silently re-hashes it with Argon2id. No action is needed from you or your members.

What This Means for You

Even if someone gains access to your database, they cannot read your members' passwords. The upgrade from MD5 happens invisibly, so your members never notice the transition.

CSRF

Form Protection

What Luster Does

Every form in Luster includes a hidden security token. When the form is submitted, Luster checks that the token matches the one it generated for that session. This is called CSRF (Cross-Site Request Forgery) protection.

If a malicious site tries to trick a logged-in admin into submitting a form, the token will be missing or wrong, and Luster will reject the request.

What This Means for You

No one can forge form submissions on your behalf. Every state-changing action, whether it comes from the admin panel or a public form, is verified before it runs.

XSS Prevention

Output Escaping

What Luster Does

Every value displayed on the page is escaped before it reaches the browser. Special characters like <, >, &, and " are converted to safe equivalents so they are displayed as text, not interpreted as code.

This prevents Cross-Site Scripting (XSS), where an attacker injects malicious JavaScript through form fields or URLs.

What This Means for You

If someone enters a script tag in a join form or member name, it is rendered as harmless text. Your visitors are never exposed to injected scripts.

SQL Injection

Database Protection

What Luster Does

Luster uses prepared statements for every database query. The query structure and the data are sent to the database separately, so user input can never alter the meaning of a query.

This completely prevents SQL injection, one of the most common and dangerous web vulnerabilities.

What This Means for You

An attacker cannot manipulate your database by entering crafted values into forms or URLs. Your data stays exactly where it belongs.

Sessions

Session Security

What Luster Does

Luster configures session cookies with four protective flags:

  • HttpOnly — JavaScript cannot read the session cookie, blocking cookie-theft scripts.
  • Secure — the cookie is only sent over HTTPS, preventing interception on unencrypted connections.
  • SameSite=Strict — the cookie is never sent with cross-site requests, adding another layer of CSRF defence.
  • Session regeneration on login — a new session ID is issued after every successful admin login, so a stolen pre-login session ID is useless.

What This Means for You

Your login session is locked down from multiple angles. Attackers cannot steal, hijack, or reuse your session through common browser-based attacks.

Uploads

File Upload Safety

What Luster Does

When a file is uploaded, Luster checks the actual file content to determine its type, not the file extension. A file named photo.jpg that is actually a PHP script will be rejected.

Uploaded files are saved with randomised filenames so attackers cannot guess or target them. The uploads directory has an .htaccess rule that blocks PHP execution entirely, so even if a malicious file slipped through, it could not run.

What This Means for You

Uploaded files cannot be used as a backdoor into your server. The combination of content-based validation, random naming, and execution blocking creates multiple layers of defence.

SSRF Protection

Outbound Connection Safety

What Luster Does

When Luster makes an outbound HTTP request — checking affiliate links, fetching remote images during import, or verifying your TFL/TAFL registration — it resolves the hostname to an IP address first and checks that the address is public. Private and internal network addresses are blocked.

The connection is pinned to the resolved IP so a DNS rebinding attack cannot redirect the request after validation. Response size is capped to prevent resource exhaustion.

What This Means for You

An attacker cannot trick Luster into making requests to your internal network or local services. The link checker and other outbound features are safe to use.

Rate Limiting

Brute-Force Protection

What Luster Does

Luster rate-limits admin login attempts, password reset requests, and public form submissions. After too many failed attempts from the same address, further requests are temporarily blocked.

What This Means for You

An attacker cannot guess passwords by trying thousands of combinations. The rate limiter slows them down dramatically, making brute-force attacks impractical.

Anti-Spam

Bot Protection

What Luster Does

Public forms include a honeypot field, an invisible input that real users never fill in but automated bots do. Forms also include a simple math CAPTCHA that asks the visitor to solve a short arithmetic question.

What This Means for You

Most spam bots are caught before their submissions reach you. The math CAPTCHA is simple enough for real visitors but effective against automated scripts. No third-party CAPTCHA service is needed.

Authentication

Remember-Me Tokens

What Luster Does

When you tick “Keep me signed in” on the admin login form, Luster issues a per-device remember-me token:

  1. A 256-bit random token is generated — only a SHA-256 hash is stored in the database; the raw token is placed in your cookie and never recorded anywhere.
  2. Luster keeps one token per device or browser, up to a maximum of 10 per admin account. The oldest is removed automatically when the cap is reached.
  3. Each time you are re-authenticated via a remember-me cookie, the token is rotated: the old token is invalidated and a fresh one is issued, so a stolen cookie cannot be replayed if you have already visited since the theft.
  4. Tokens expire automatically after 30 days.
  5. All remembered devices are invalidated immediately when you change your password.

What This Means for You

You can stay signed in safely across multiple browsers or devices. If you suspect a device has been compromised, go to Settings → Remembered Devices to revoke one or all at once. Changing your password revokes every remembered device everywhere automatically.

Password Resets

Secure Password Resets

What Luster Does

When a password reset is requested, Luster generates a 256-bit random token. Only a hash of the token is stored in the database; the raw token is sent to the user's email. Tokens expire after one hour.

Whether a reset request matches a real account or not, Luster always shows the same neutral confirmation message. This prevents attackers from using the reset form to discover which email addresses are registered.

What This Means for You

Even if an attacker accesses the database, they cannot use stored token hashes to reset passwords. Short expiry windows and one-time use further limit the attack surface.

File Protection

Source Code Protection

What Luster Does

Only the public/ directory is web-accessible. Source code, configuration, database backups, import temp files, and all internal logic live outside that folder where browsers cannot reach them. On top of that, multiple layers of .htaccess protection are in place:

  • A root .htaccess blocks direct web access to everything outside public/ — source code in src/, your config/app.php (which holds your database password), backup ZIPs in storage/cache/, Composer files, documentation, tests, and the .git directory are all denied.
  • A storage/.htaccess denies all access to logs, cache files, and temporary import data as a second layer of defence.
  • A config/.htaccess protects your configuration file specifically.
  • The public/uploads/ .htaccess blocks PHP execution in the uploads directory so uploaded files can never run as code.
  • The public stylesheet is served through a PHP proxy (?luster_css) instead of a direct file link, so visitors never see where Luster is installed on your server. Comments are also stripped from the served CSS to avoid leaking path hints or software identifiers.

What This Means for You

Even if someone knows your Luster URL, they cannot browse your PHP source code, download your configuration file, access backup ZIPs that contain database dumps, view your .git history, or see where Luster is installed on your server. Your code and data stay private.

Testing

Automated Testing

What Luster Does

Luster has over 1,900 automated tests that run against every change. These tests verify that security features work correctly, that input validation catches bad data, and that edge cases are handled safely.

What This Means for You

Bugs and regressions are caught before they reach you. The test suite acts as a safety net that ensures security protections stay in place as the codebase evolves.

Import Security

Import Safety

What Luster Does

When you import data from another script, the source database credentials are stored in the session only, cleared automatically once an import succeeds, and cleared unconditionally the next time you open the import page — a failed run deliberately leaves them in place in between, so you can retry without retyping everything. Luster never writes to the source database.

All table and column names are validated before they are used in queries. Each row is imported inside its own error boundary, so one bad record does not abort the entire import.

What This Means for You

Your old database is never modified during import. Credentials are not persisted anywhere on disk. If a single record has bad data, the rest of the import continues normally.