| name | security |
| description | Maintain and improve security across the Zelaxy platform. Use for: secret encryption boundaries, auth modes (session/API key/internal JWT/cron), CSP and middleware hardening, webhook verification, tenant isolation, and security test coverage. |
Security Skill - Zelaxy
Purpose
Modify and review security-sensitive code using repository-accurate behavior, not generic web-security assumptions.
Non-Negotiable Rule: Security Changes Require Tests
If authentication, authorization, credential handling, CSP, middleware filtering, webhook verification, or rate limiting changes:
- Add or update tests for changed behavior.
- Run targeted security-relevant tests before completion.
- Report exact commands and outcomes.
- If no existing tests cover a touched path, add coverage or explicitly call out the unverified risk.
When to Use
- Handling encrypted secrets and environment variables
- Changing auth checks in API routes, middleware, webhooks, or sockets
- Modifying internal service authentication (JWT, cron auth, internal API key)
- Hardening CSP/CORS/headers
- Updating rate-limiting behavior
- Auditing tenant/organization data isolation
Security Architecture Map (High-Impact Files)
- Secret encryption helpers:
apps/zelaxy/lib/utils.ts
- Auth configuration:
apps/zelaxy/lib/auth.ts
- Internal auth helpers:
apps/zelaxy/lib/auth/internal.ts
- Hybrid auth helper:
apps/zelaxy/lib/auth/hybrid.ts
- Global middleware:
apps/zelaxy/middleware.ts
- CSP builders:
apps/zelaxy/lib/security/csp.ts
- Security headers/CORS:
apps/zelaxy/next.config.ts
- Workflow API key access guard:
apps/zelaxy/app/api/workflows/middleware.ts
- Workflow execute route:
apps/zelaxy/app/api/workflows/[id]/execute/route.ts
- Webhook trigger route:
apps/zelaxy/app/api/webhooks/trigger/[path]/route.ts
- Socket token route:
apps/zelaxy/app/api/auth/socket-token/route.ts
- Socket auth middleware:
apps/zelaxy/socket-server/middleware/auth.ts
- Socket CORS/cookie config:
apps/zelaxy/socket-server/config/socket.ts
- Rate limiter:
apps/zelaxy/services/queue/RateLimiter.ts
- Permissions checks:
apps/zelaxy/lib/permissions/utils.ts
- Core schema contracts:
apps/zelaxy/db/schema.ts
Runtime Security Model (Current Behavior)
1) Secret encryption boundaries
encryptSecret/decryptSecret use AES-256-GCM with a random 16-byte IV.
- Encrypted format is
iv:ciphertext:authTag (hex).
ENCRYPTION_KEY must be a 64-character hex string (32 bytes) or encryption/decryption throws.
- User/org environment-variable routes encrypt at rest and decrypt on read/execution.
- Important boundary: Better Auth account tokens (
account.accessToken, account.refreshToken) are not passed through encryptSecret in app code paths.
2) API key model for workflow execution
- API keys are generated by
generateApiKey() as Zelaxy_${nanoid(32)}.
- API keys are stored in
api_key.key and compared directly.
- Workflow deployment can pin a specific key in
workflow.pinnedApiKey.
validateWorkflowAccess(..., requireDeployment=true) enforces:
- workflow must be deployed
x-api-key header is required
- if pinned key exists, it must match exactly; otherwise key must belong to workflow owner
3) Authentication modes across the platform
- Session auth:
getSession() backed by Better Auth cookies.
- Internal JWT auth:
generateInternalToken() + verifyInternalToken() (HS256, 5m expiry, issuer/audience checks).
- Cron auth:
verifyCronAuth() expects Authorization: Bearer ${CRON_SECRET}.
- Internal API key auth: selected routes compare
x-api-key against env.INTERNAL_API_SECRET.
- Socket auth: one-time token generated via
/api/auth/socket-token, verified server-side with auth.api.verifyOneTimeToken.
4) Middleware, CSP, and headers
- Middleware blocks suspicious user agents with 403 and strict no-cache/no-sniff headers.
/api/webhooks/trigger/* is exempt from suspicious-user-agent blocking.
- Runtime CSP (
generateRuntimeCSP) is applied in middleware for /, /arena/*, /chat/*.
- Build-time headers in
next.config.ts set CORS and security headers for broader route sets.
/api/workflows/:id/execute uses a deliberately permissive CSP from getWorkflowExecutionCSPPolicy().
5) Rate limiting behavior
RateLimiter applies per-plan sync/async limits for api, webhook, schedule, and chat trigger types.
- Manual trigger type bypasses limits (
MANUAL_EXECUTION_LIMIT).
- Limits are tracked in
user_rate_limits with windowed counters.
- Fail-open behavior: rate-limiter errors return
allowed: true to avoid blocking users.
- Webhook trigger route returns status 200 on rate-limit exceed to reduce provider retries.
6) Webhook verification model
- Webhook trigger route validates active webhook path in DB before execution.
- Provider-specific handling includes:
- WhatsApp verification challenge
- Slack challenge handling
- Microsoft Teams HMAC validation (when configured)
- Payload parsing handles both JSON and form-encoded payloads.
- Do not assume helper-only verification functions run automatically for every provider; enforce explicit checks in route flow when adding providers.
7) Tenant and permission boundaries
- Org environment API enforces membership for read and owner/admin for write.
- Workflow GET/PUT/DELETE route enforces owner/workspace permissions.
- Socket permission middleware maps workflow ownership/workspace membership to role-based operation allowlists.
- Environment-variable routes scope reads/writes by authenticated user context.
Security-Critical Pitfalls (Current Codebase)
validateWorkflowAccess(request, id, false) does not enforce session or API-key auth by itself.
getUserId(requestId, workflowId) resolves workflow owner without session checks (safe only in trusted internal call paths).
- API keys and pinned keys are stored/compared as plain text values.
env uses skipValidation: true, so configuration mistakes can bypass startup validation.
- Workflow execution CSP is intentionally permissive.
- Several secret comparisons use direct equality (not constant-time), except specific hardened checks.
Implementation Checklist
For new/changed security-sensitive routes and services:
- Choose auth mode intentionally (session, API key, internal JWT, cron) and enforce it in the route.
- Validate input with Zod before DB/tool calls.
- Enforce tenant scope (
userId, workspaceId, organizationId) on every data access.
- Encrypt secrets at rest when using app-managed secret stores.
- Never log raw secrets, tokens, API keys, or decrypted environment values.
- Add/verify rate limiting where endpoints are externally callable.
- Re-check CORS/CSP implications when adding new execution or integration surfaces.
PR Review Checklist (Security)
- Can any route be reached without the intended auth check?
- Are workflow/org/workspace boundaries enforced in queries?
- Are secrets encrypted where expected and omitted from logs/responses?
- Did changes accidentally relax CSP/CORS/headers?
- Are webhook signature/token checks correctly wired in request flow?
- Are rate-limit bypass/fail-open decisions explicit and documented?
- Were targeted tests added/updated and run?
Test Expectations
Run in apps/zelaxy:
bun run test -- lib/utils.test.ts
bun run test -- services/queue/RateLimiter.test.ts
bun run test -- app/api/auth/oauth/utils.test.ts
bun run test -- app/api/workflows/[id]/execute/route.test.ts
bun run test -- app/api/workflows/[id]/deploy/route.test.ts
bun run test -- app/api/webhooks/trigger/[path]/route.test.ts
bun run test -- socket-server/index.test.ts
Add coverage when touching currently weakly-covered paths such as:
apps/zelaxy/middleware.ts
apps/zelaxy/app/api/workflows/middleware.ts
apps/zelaxy/lib/auth/internal.ts
apps/zelaxy/lib/auth/hybrid.ts