Security Model
Dualis Finance implements a defense-in-depth security architecture spanning five layers: authentication, API hardening, access control, smart contract safety, and infrastructure resilience. Every layer is designed to fail independently, so a breach in one does not compromise the others.
Security Layers
The following table summarizes the security controls deployed across each layer of the Dualis stack. Together, they form a comprehensive perimeter that protects user assets, sensitive data, and protocol operations.
| Layer | Controls | Details |
|---|---|---|
| Authentication | JWT + bcrypt | Stateless JWT tokens with configurable expiration. Passwords hashed with bcrypt using a cost factor of 12. Refresh token rotation prevents session hijacking. Canton wallet authentication via PartyLayer signature verification. |
| API Hardening | Rate limiting, Helmet, CORS, CSRF, Zod | Rate limiting via Redis-backed sliding window (configurable per-endpoint). Helmet sets security headers including CSP, HSTS, and X-Frame-Options. CORS restricted to allowed origins. CSRF tokens on state-changing requests. All request bodies validated with Zod schemas -- invalid payloads are rejected before reaching business logic. |
| Access Control | RBAC, admin audit logging | Role-based access control with four roles: user, institutional, admin, and super-admin. Administrative actions (parameter changes, pool creation, emergency pause) are logged to an immutable audit trail in PostgreSQL. Sensitive operations require multi-step confirmation. |
| Smart Contracts | DAML signatory model | DAML's signatory/observer model ensures no contract can be created or exercised without explicit authorization from required parties. No reentrancy is possible due to DAML's atomic execution model. All asset transfers require the asset owner's signature. The functional type system eliminates overflow, underflow, and null pointer vulnerabilities at compile time. |
| Infrastructure | Circuit breaker (Opossum), Sentry, TLS | Opossum circuit breakers protect against cascading failures when downstream services (Canton, oracles) become unresponsive. Sentry captures and alerts on runtime errors across API and frontend. All traffic encrypted via TLS 1.3 with Let's Encrypt certificates. Docker containers run with minimal privileges. |
Defense in Depth
The security architecture is designed so that no single control is a single point of failure. Even if an attacker bypasses rate limiting and exploits an API vulnerability, they still face RBAC enforcement, Zod validation, DAML signatory requirements, and audit logging. Each layer operates independently:
- Perimeter: Nginx reverse proxy with TLS termination, IP-based rate limiting, and request size limits.
- Application: Fastify middleware chain -- authentication, CORS, CSRF, Helmet headers, Zod schema validation -- runs before any route handler.
- Business logic: RBAC checks verify the authenticated user has the required role for the requested operation. Pool limits and position constraints are enforced server-side.
- Settlement: DAML contracts on Canton provide the final authorization layer. Even if the API is compromised, Canton will reject any transaction that lacks proper signatory authorization.
- Monitoring: Sentry error tracking, structured logging, and admin audit trails provide real-time visibility into anomalous behavior.
Input Validation
Every API endpoint validates its request body, query parameters, and path parameters using Zod schemas. These schemas are defined alongside the route handlers and enforce type safety, value ranges, and format requirements. Examples include:
- Amount fields must be positive decimals with a maximum precision of 18 decimal places.
- Address fields must match Canton party ID format.
- Enum fields (asset type, credit tier, order side) must be one of the allowed values.
- Pagination parameters are bounded to prevent resource exhaustion.
Requests that fail validation receive a structured error response with field-level details, enabling clients to display meaningful error messages without exposing internal implementation details.
Error Handling
The API uses a centralized error mapper (error-mapper.ts) that translates raw Canton errors, database errors, and internal exceptions into user-friendly error responses. Raw error details are logged to Sentry but never exposed to clients. This prevents information leakage that could aid an attacker in understanding the system's internal architecture.