Skip to Content
Ranlanka CRM documentation — pre-release, subject to change.
Security

Security

Authentication

JWT is delivered via an HTTP-only cookie — never stored in localStorage, so it isn’t reachable from client-side JavaScript (mitigates XSS-driven token theft). CSRF protection uses a double-submit cookie pattern (XSRF-TOKEN cookie + matching request header on mutating requests).

Login is rate-limited: repeated failed attempts lock the account temporarily.

Password reset

Password reset is OTP-verified, not link-based:

  1. POST /auth/forgot-password requires both the email and the account’s mobile number to match — a single leaked email address isn’t enough to trigger a reset.
  2. On a match, an OTP is emailed, and every owner account is alerted immediately (even before the OTP is verified).
  3. POST /auth/forgot-password/verify-otp checks the code and only then issues a short-lived reset token.
  4. POST /auth/reset-password consumes that token once.

Authorization (RBAC)

Permissions are database-backed (roles / role_permissions tables), checked via @PreAuthorize("hasAuthority('X')") on service methods — not a hardcoded Java enum. This means new permissions can be granted or revoked without a deploy.

Ownership checks — for “my own resource” style access (e.g. a staff member acting on a customer assigned to them), an @RequireOwnership aspect compares the resource’s assigned owner against the acting staff member, with admin roles bypassing the check. If a resource has no owner assigned yet, the check is deliberately skipped, not denied, so unassigned work stays visible and claimable.

Role escalation is separately guarded — granting the owner role to another account requires the acting user to already be an owner, even though the same base permission (STAFF_MANAGE) is also held by manager for unrelated reasons.

Dev-only bypass flags

A small number of environment flags exist purely for local development and are refused at application startup if left true outside a local/dev profile:

FlagEffect
app.security.disable-authzBypasses all @PreAuthorize checks (still requires login)
app.security.disable-authnSkips login entirely, auto-authenticates as the first active staff member
app.scheduler.dev-fast-modeRe-runs scheduled jobs every 10s instead of waiting for the daily cron

Each is backed by a @PostConstruct guard that throws on startup if the flag is enabled outside an allowed profile — this is a hard stop, not just a warning.

Email content

Every value substituted into an HTML email template is HTML-escaped by default — a staff-entered name or note can’t inject markup into an email rendered by a real mail client. The one exception is server-generated URLs (e.g. resetLink), which skip escaping so & in the query string isn’t corrupted. Server-built HTML fragments (not user input) that legitimately need to render as markup go through a separate, explicitly-named method rather than being smuggled through the escaped path.

Reporting a vulnerability

This project does not yet have a public security disclosure process. If you’ve found an issue, contact the maintainer directly rather than opening a public issue.

Last updated on