🔒
Security
Built in layers — from login to OWASP Top 10.
SMS-based two-factor authentication, role-based access control, brute-force protection, HTTP security headers, audit log over every action and automatic OWASP ZAP scanning on every pull request.
- SMS-based 2FA with 10-minute one-time codes
- Role-based access on pages and API endpoints
- Brute-force protection with per-endpoint rate limits
- OWASP Top 10 compliance with weekly ZAP scanning
Security isn't a feature — it's foundation
Every layer is built with security in mind. Login is protected by brute-force rate limits and optional two-factor authentication. Every page and every API endpoint checks permissions on every call — not just at login. SQL injection is impossible (parameterised queries), XSS is blocked (DOMPurify), CSRF attacks are prevented (SameSite=lax cookies), and clickjacking is stopped via the X-Frame-Options header.
Every action is logged. The audit log shows who did what in the admin panel. The security log shows failed login attempts, 2FA events, access denied and rate-limit breaches. The system is audited against OWASP Top 10, and OWASP ZAP scanning runs automatically on every pull request to main.
Parameterised SQL queries — no injection possible
DOMPurify cleans user-supplied HTML — no XSS
Session cookies HttpOnly + Secure + SameSite=lax
Audit log over every admin action
Security log over failed logins and 2FA events
Dependabot + composer/npm audit on every build
Two-factor authentication (2FA)
SMS-based
Staff can enable SMS-based 2FA on their account.
6-digit one-time code
On login, a 6-digit code is sent via SMS that must be confirmed before access is granted.
10-minute validity
Codes expire after 10 minutes and can only be used once.
Logged in the security log
Every 2FA event — completed and failed — is recorded.
Role-based access control
Every part of the system is protected by named permissions.
Per-page permissions
Users only get access to the parts of the system their role allows.
Menu items hidden automatically
Items without permission do not appear in the menu — so users never see buttons they cannot use.
Attempts logged
Attempts to access pages without permission are logged in the security log.
Managed in-product
The permission structure is maintained under Settings → Roles and permissions.
Brute-force protection
Three layers of rate limits protect against overload and attack.
Login lockout
Too many failed attempts result in a temporary lockout.
General: 60/min
60 requests per minute for every authenticated endpoint.
Search: 30/min
30 requests per minute for search endpoints.
Bulk lookup: 20/min
20 requests per minute for bulk lookups.
Standardised error
Exceeding the limit returns a standard error response with retry-after info.
HTTP security headers
Every response includes protective headers.
Strict-Transport-Security
Enforces HTTPS — prevents eavesdropping.
X-Content-Type-Options
Blocks MIME-sniffing attacks.
X-Frame-Options
Protects against clickjacking — the system cannot be embedded on foreign sites.
Referrer-Policy
Prevents leakage of internal URLs to third parties.
Permissions-Policy
Blocks unauthorised use of camera, microphone and location.
Input validation and injection protection
Parameterised queries
All database access uses the Eloquent ORM — SQL injection is impossible.
Per-endpoint validation
Every API endpoint validates incoming data before processing.
DOMPurify against XSS
User-supplied HTML is cleaned with DOMPurify before display.
MIME and extension validation
Uploaded files are validated on type and extension and stored outside the web root.
Audit log and security log
Audit log over admin actions
Every call to the admin panel is logged with user ID, URL, HTTP method, IP and timestamp.
Sensitive fields scrubbed
Passwords and API keys are scrubbed automatically before logging.
Security log
Failed logins, 2FA events, access denied and rate-limit breaches are recorded separately.
Read-only
The security log is read-only and accessible to administrators.
OWASP Top 10 and vulnerability scanning
The system is audited against OWASP Top 10 (2021) and hardened on all 10 categories.
Broken access control
Role-based permissions on every page and API endpoint.
Cryptographic failures
HTTPS, secure cookies, hashed one-time codes.
Injection
Eloquent ORM and input validation — no raw SQL with user input.
OWASP ZAP scanning
Baseline scanning runs on every pull request to main and weekly. High-risk findings block merge.
composer + npm audit
Runs on every CI build and stops deploy on critical package vulnerabilities.
Dependabot
Monitors dependencies weekly and opens pull requests for updates automatically.
Responsible disclosure
info@ziix.dk
Security issues are reported privately with subject "[SECURITY] DMS Vulnerability Report".
Acknowledgement within 48 hours
Critical issues targeted for fix within 30 days.