Skip to main content

Security

Unchained Engine implements security best practices for e-commerce applications.

Full Security Documentation

For detailed security documentation including compliance information and deployment recommendations, see the SECURITY.md file in the repository.

Cryptographic Standards​

Password Hashing​

  • Algorithm: PBKDF2 with SHA-512
  • Iterations: 300,000 (exceeds OWASP recommendation of 210,000)
  • Salt: 16 bytes, cryptographically random
  • Key Length: 256 bits (32 bytes)
  • Implementation: Web Crypto API (crypto.subtle)

Access Tokens (Sessions)​

  • Format: JWT, signed with HS256 (jose)
  • Secret: UNCHAINED_TOKEN_SECRET, minimum 32 characters (enforced at boot)
  • Expiry: UNCHAINED_TOKEN_EXPIRY_SECONDS, default 3600 (1 hour)

Verification & Reset Tokens​

  • Generation: crypto.randomUUID() (CSPRNG-based)
  • Storage: SHA-256 hashed before database storage

Payment Security​

Unchained never stores card data:

  • Credit card numbers (PAN) are never stored
  • CVV/CVC codes are never stored
  • Payment adapters only store provider-side transaction references and tokens

Bundled payment integrations: Stripe, Datatrans, PostFinance Checkout, Saferpay, Payrexx, Apple IAP, Cryptopay, and invoice-based flows. See Payment Integration.

Access Control​

Role-Based Access Control (RBAC)​

  • Over 100 defined actions covering all API operations
  • Built-in roles: admin, logged-in user, plus special roles for guests
  • Ownership validation: Users can only access their own resources
// Example permission check
role.allow(actions.updateOrder, async (order, params, context) => {
return order.userId === context.userId;
});

See Permissions for defining custom roles via rolesOptions.

Audit Logging​

Unchained provides OCSF-compliant (Open Cybersecurity Schema Framework) audit logging designed for consumption by external monitoring agents:

  • OCSF v1.4.0 schema - Industry-standard format supported by AWS Security Lake, Datadog, Splunk, Google Chronicle
  • Structured emission by default - Every event as one JSON log line on stdout (UNCHAINED_LOG_FORMAT=json), scrapeable by any log agent
  • OTLP push - Optional OTLP/HTTP push to any OpenTelemetry-compatible collector (collectorUrl or OTEL_EXPORTER_OTLP_* env)

The engine does not persist audit events itself — retention, queries, and integrity guarantees are the consuming log pipeline's or SIEM's concern.

Audit logging is automatically enabled when using startPlatform() — events are emitted through the unchained:audit logger; OTLP push is opt-in.

// Opt-in OTLP push:
const platform = await startPlatform({
auditLog: {
collectorUrl: 'http://otel-collector:4318/v1/logs',
},
});

// Automatically captured (97 event types): login/logout/failed login,
// user creation/deletion, password changes, role changes, order checkout,
// payments, access denied

See Audit Logging for detailed documentation.

Input Validation​

ReDoS Prevention​

All user-supplied strings used in regular expressions are escaped:

import { escapeRegexString } from '@unchainedshop/mongodb';

const regex = new RegExp(escapeRegexString(userInput), 'i');

Timing Attack Prevention​

Security-sensitive string comparisons use constant-time algorithms:

import { timingSafeStringEqual } from '@unchainedshop/utils';

if (await timingSafeStringEqual(providedToken, expectedToken)) {
// Token is valid
}

Session Cookies​

The JWT is delivered as an httpOnly cookie with these defaults:

{
httpOnly: true, // always true, prevents XSS access
secure: true, // unless UNCHAINED_COOKIE_INSECURE is set
sameSite: 'lax', // OWASP: CSRF protection
maxAge: 3600 * 1000, // follows UNCHAINED_TOKEN_EXPIRY_SECONDS
}
VariablePurposeDefault
UNCHAINED_TOKEN_SECRETJWT signing secret (min 32 chars)Required
UNCHAINED_TOKEN_EXPIRY_SECONDSToken and cookie lifetime3600
UNCHAINED_COOKIE_NAMECookie nameunchained_token
UNCHAINED_COOKIE_DOMAINCookie domain restriction-
UNCHAINED_COOKIE_SAMESITESameSite attribute (strict, lax, none)lax
UNCHAINED_COOKIE_INSECUREDisable secure flag (development only)-

Error Handling​

Errors are designed to prevent information leakage:

  • Permission errors: Generic "not authorized" responses
  • User enumeration prevention: forgotPassword returns success regardless of whether the user exists

Rate Limiting​

Rate limiting should be implemented at the reverse proxy level (nginx, Cloudflare, AWS ALB):

# nginx example
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s;

server {
location /graphql {
limit_req zone=api burst=50 nodelay;
proxy_pass http://unchained:3000;
}
}
EndpointRecommended LimitRationale
Login mutations5/minute per IPPrevent brute force
Password reset3/hour per IPPrevent enumeration
Registration10/hour per IPPrevent spam
GraphQL queries100/second per IPGeneral protection

Reporting Vulnerabilities​

If you discover a security vulnerability:

We will acknowledge receipt within 48 hours and provide a detailed response within 7 days.