Security and privacy

How we protect your people's data.

28 security practices grouped into 6 domains: encryption, authentication, multi-tenancy, AI, compliance, and web hardening. We operate in AWS sa-east-1 with a DPA available for every customer.

Layer 1

Encryption & Data Residency

All sensitive data is encrypted at rest with AES-256-GCM and in transit with TLS 1.3. Your information lives in AWS sa-east-1 (São Paulo) and never leaves the region without your consent.

AES-256-GCM encryption at rest

AES-256-GCM encryption applied to sensitive database fields: user and employee emails, TOTP secret for 2FA, API tokens for your HRIS integrations, OIDC client secret, and the RUT (tax ID) in billing data.

Keys are managed via AWS KMS in production with incremental rotation support. For lookups that don't require decryption (authentication, person search), we use deterministic SHA-256 hashes in composite indexes.

TLS 1.3 in transit

All traffic between browser, CloudFront, nginx, API, and database travels over TLS 1.3 with modern ciphers. HSTS preload with max-age of 2 years and includeSubDomains to ensure no browser ever downgrades to HTTP.

Data residency: AWS sa-east-1 (São Paulo)

Your database (Neon PostgreSQL serverless), Redis, S3, and compute infrastructure live in AWS sa-east-1. Data doesn't leave the region without your explicit authorization.

Only exception: calls to Claude (Anthropic) and Voyage AI (embeddings) travel outside the region, but with PII redacted and under enterprise contract that prohibits training.

Deterministic SHA-256 lookups

To search users by email without needing to decrypt (login, password reset, invite), we store an emailHash SHA-256 in a composite index (companyId, emailHash). This avoids decrypting the field on each request and removes the risk of timing-based side-channel attacks in queries.

Same pattern for RefreshToken.tokenHash, ApiKey.keyHash, InviteToken.token, and PasswordResetToken.token.

Layer 2

Authentication & Access

Modern authentication: JWT in HttpOnly cookies, rotation with theft detection, 2FA TOTP + passkeys, enterprise SSO with SCIM, and HIBP validation. No shortcuts.

HttpOnly cookies with separate paths

JWTs travel in HttpOnly, SameSite=None, Secure cookies, inaccessible from client-side JavaScript (prevents XSS theft).

Cookies are split by path: access_token (15 min) on path / and refresh_token (7 days) on path /api/v1/auth/refresh. This way the refresh is only sent when actually needed, reducing its exposure.

Refresh token rotation with theft detection

Each refresh token is single-use. If the same token arrives twice (usedAt already set), we assume possible theft: automatically invalidate ALL of the user's tokens by incrementing tokenVersion and force a re-login.

Tokens are stored as SHA-256 hashes, never in plaintext. Rotation drastically reduces the attack window if a token leaks.

Token revocation without a DB blacklist

Logout doesn't require querying a blacklist in the database on every request. We increment a tokenVersion field on User, and our JWT strategy compares payload.tv === user.tokenVersion. Any JWT issued before logout stops validating instantly.

Upside: zero per-request latency (no extra query) and the ability to invalidate ALL sessions of a user in a single atomic change.

2FA TOTP + WebAuthn / Passkeys

Full TOTP 2FA support (Google Authenticator, Authy, 1Password). The secret is stored AES-256-GCM encrypted with a dedicated key (TOTP_ENCRYPTION_KEY), separate from the main key.

When 2FA is enabled, we generate 10 bcrypt-hashed backup codes for recovery. We also support WebAuthn / passkeys, enabling passwordless login with Face ID, Touch ID, Windows Hello, or hardware keys (YubiKey).

SAML/OIDC SSO + SCIM (Enterprise preview)

SsoConfig model active for Enterprise customers: stores SAML entryPoint, issuer and IdP certificate, plus OIDC credentials encrypted at rest with AES-256-GCM. The OIDC client secret is never exposed in plaintext outside the moment of creation.

SCIM 2.0 provisioning available in preview: /scim/v2/Users endpoint with Bearer token (SHA-256 hash in DB, shown in plaintext only once at generation) lets your IdP create and disable users. The full SSO login flow (signed SAML assertion validation and OIDC token exchange) is on the Enterprise roadmap — available on request for early evaluation.

Strong passwords + lockout + anti-enumeration

We validate every password against HIBP (Have I Been Pwned) using k-anonymity: we only send the first 5 characters of the SHA1 hash, never the full password. If it appears in public breaches, we reject it.

Automatic lockout after 5 failed attempts (15 min block). Login and forgot-password always return the same generic message, preventing email enumeration.

Layer 3

Hermetic Multi-tenancy

Isolation between companies doesn't depend on the developer: our ORM layer filters by `companyId` automatically on every query. The system fails before leaking.

Multi-tenancy with PostgreSQL Row-Level Security

Real defense-in-depth at the database layer. Every tenant-scoped table has ROW LEVEL SECURITY policies that filter by company_id automatically — even if an application query forgot the filter, PostgreSQL returns 0 rows without error.

The PrismaService (REQUEST-scoped) executes SET LOCAL app.company_id = '<uuid>' at the start of every transaction, reading the id from an AsyncLocalStorage populated by the TenantContextMiddleware. The policies use current_setting('app.company_id')::uuid to compare. Background jobs and schedulers run inside runWithCompany(companyId, fn), ensuring no operation ever touches data outside its tenant.

Isolation by JWT + Membership check

The companyId never travels in the body of a request. It's always read from the X-Company-ID header, and we validate that the authenticated user has a Membership in that company before continuing.

This means that even with a stolen JWT, you cannot access another company's data: the JwtAuthGuard rejects the request if it doesn't find a matching membership.

Fail-closed: unknown model = exception

The Prisma middleware has two explicit lists: SCOPED_MODELS (54 models that require a companyId filter) and ALLOWED_MODELS (global models without tenant: enums, plan catalog, etc.).

Any model not in either list triggers an immediate exception. It's impossible to accidentally introduce a new model without going through an explicit security code review.

Layer 4

AI with Guardrails

AI is a safe copilot: PII redacted before each prompt, 18 injection patterns blocked, and enterprise contracts that prohibit training with your data.

PII redacted before every call to Claude

Before sending any prompt to Claude (Anthropic), we automatically redact:

  • Emails → [EMAIL_REDACTED]
  • Chilean RUT → [RUT_REDACTED]
  • Phone numbers → [PHONE_REDACTED]
  • Salaries (CLP / USD / UF) → [SALARY_REDACTED]

The model works with symbolic representations, not real personal data. Each redaction is logged in PromptGuardrailEvent for auditing.

18 prompt injection patterns blocked

We recognize and block 18 distinct prompt injection patterns: 'ignore previous instructions', 'DAN mode', 'jailbreak', 'pretend you are', 'forget your rules', 'override your instructions', 'role play as', 'developer mode', 'simulate being', among others.

Each attempt is logged with the input's SHA-256 hash (not the content) in PromptGuardrailEvent, along with userId and companyId, to detect systematic abuse.

Boundary markers separating data from instructions

When we inject company data into a RAG prompt, we wrap it in clear markers: <<<COMPANY_DATA>>>...<<<END_COMPANY_DATA>>> and <<<USER_QUESTION>>>...<<<END_USER_QUESTION>>>.

This prevents prompt confusion: the model distinguishes what is factual context from your company, what is the user's question, and what are its own system prompt instructions. Recommended pattern in LLM safety literature.

Your data does not train public models

We use Anthropic Claude on enterprise tier: by contract, no input or output is used to train public models. Same with Voyage AI (embeddings): it does not store queries.

There is no model fine-tuning with one customer's data that benefits another. Your information stays with you.

Fallback to deterministic rules

Every recommendation has two layers: Layer 1 (deterministic rules) always runs and guarantees a response, and Layer 2 (Claude) enriches with qualitative judgment.

If the AI fails for any reason (rate limit, timeout, network error, invalid output), the rules layer responds. The client never sees a blank screen and there's no degradation in security.

Layer 5

Compliance & Auditing

We operate under Chilean Law 19.628, Brazilian LGPD, and GDPR as a baseline. Every critical action is in an immutable AuditLog, and you have export + delete with one click.

Law 19.628 — Personal Data Protection (Chile)

We operate under the standards of Law 19.628 on Privacy Protection in Chile. Your employees' personal data is processed with consent, specific purpose, and right of access/rectification/cancellation.

DPA (Data Processing Agreement) document available for any customer that requires it.

LGPD — Lei Geral de Proteção de Dados (Brazil)

We comply with Brazilian LGPD: clear legal bases for each processing, data subject rights (access, correction, deletion, portability), and incident notification within reasonable timeframes.

For Brazilian customers, the LGPD-specific DPA and Data Protection Officer contact are available on request.

GDPR — European rights compliance

Although our focus is LATAM, we implement GDPR rights as a baseline: portability (ZIP export with all your data in JSON), right to be forgotten (soft/hard delete with anonymization), minimization (we only collect what's needed), and transparency (this page).

Certification roadmap — ISO 27001 / SOC 2

We operate with controls equivalent to ISO 27001 (AES-256-GCM at rest, fail-closed tenant segregation with DB-level RLS, immutable audit log, mandatory 2FA on Enterprise plans, GDPR hard-delete, prompt-injection guardrails, etc.) and an established Information Security Management System (ISMS) — 16 formal policies ratified by management on 2026-05-15. External certification is the next step.

Declared roadmap:

  • 2026 — Foundations completed: technical hardening (continuous + PostgreSQL RLS DB-level), public Trust Center (talyzr.com/security, /subprocessors, /dpa), signed DPAs with the 11 active sub-processors, 16 SEC-XXX policies formally ratified.
  • 🎯 2027 (target) — external ISO/IEC 27001:2022 audit with an accredited body (BSI / DNV / Bureau Veritas).
  • 🔍 Later — SOC 2 Type II under evaluation for US enterprise customers.

Meanwhile, we offer a bilateral DPA on request (support@talyzr.com), an up-to-date sub-processor list, and answer pre-filled security questionnaires (CAIQ Lite, SIG Lite, custom).

Immutable audit log of critical actions

Every critical action is recorded in an AuditLog table that is never deleted: USER_LOGIN, USER_LOGOUT, creation/modification/deletion of positions, successors, talent review decisions, criticality changes, platform-admin impersonations, subscription changes.

Each entry stores before/after JSON, userId, companyId, entityType, entityId, and timestamp. If a user is deleted (GDPR), their userId is anonymized but the log persists for legal compliance.

Export and delete your data at any time

As ADMIN_HR you can:

  • Export all your company's data in a ZIP with standard JSON files (right to portability).
  • Delete your personal account (soft delete with anonymization: email → deleted-{hash}@deleted.talyzr.com).
  • Delete an employee's data (soft delete preserving referential integrity).
  • Hard delete a record physically, with cascade (only ADMIN_HR).

If you cancel your subscription, data remains available for 90 days before automatic cleanup.

Electronic Invoice (DTE) for Chile

For Chilean companies that require an electronic invoice to deduct VAT, we automatically issue DTE (Documento Tributario Electrónico) upon each confirmed payment. Integration with Bsale and Nubox.

You receive PDF + XML by email with a folio assigned by the SII. The RUT in CompanyBillingInfo is stored AES-256 encrypted at rest.

Layer 6

Web Hardening & Observability

The web stack is hardened by default: HSTS, CSP in rollout, WAF v2, strict rate limiting, and Sentry monitoring with automatic PII scrubbing.

Defensive HTTP security headers by default

Full stack of defensive HTTP headers:

  • HSTS max-age=63072000; includeSubDomains; preload (2 years, preload-ready)
  • CSP (Content-Security-Policy) in Report-Only rollout — captures violations at /api/v1/csp-report before final enforce
  • X-Frame-Options DENY (anti-clickjacking)
  • X-Content-Type-Options nosniff
  • Referrer-Policy strict-origin-when-cross-origin
  • Permissions-Policy camera=(), microphone=(), geolocation=()

WAF with managed + custom rules

CloudFront protected with AWS WAFv2 applying AWSManagedRulesCommonRuleSet (OWASP Top 10), AWSManagedRulesSQLiRuleSet, and custom rate-limiting rules. Violation logs reviewed periodically to detect abuse patterns.

Global rate limiting + critical endpoints

Global IP-based throttler at 60 req/min across the API. Sensitive endpoints have stricter limits:

  • POST /auth/login: 10/min
  • POST /auth/register: 5/min
  • POST /auth/forgot-password: 3 every 15 min
  • POST /auth/2fa/verify: 5/min
  • GET /data/export: 3/min
  • DELETE /data/me: 1/min

External webhooks (Paddle, Talana, Resend) use HMAC signature + Redis idempotency for 24h.

Sentry with automatic PII scrubbing

Error monitoring with Sentry, configured with sendDefaultPii: false and a beforeSend hook that replaces emails in breadcrumbs with [email] before sending.

tracesSampleRate: 0.2 in production to keep cost controlled. Every request carries a unique requestId (ULID) propagated in headers and structured JSON logs for correlation between frontend, backend, queue, and Sentry.

Sub-processors

Vendors that touch customer data

We run talyzr on a tight set of enterprise-grade sub-processors. Each one has a DPA with us, each one meets SOC 2 / ISO 27001-equivalent standards, and the region listed is where production data resides.

VendorPurposeData region
AWSCloud infrastructure — compute (ECS/EC2), storage (S3), CDN (CloudFront), load balancing (ALB), WAFsa-east-1 (São Paulo, Brazil)
NeonServerless PostgreSQL with pgvector — production database and embeddings storeAWS sa-east-1
AnthropicClaude Sonnet for AI — talent recommendations, Taly agent, skill profiles (no training)United States
Voyage AIVector embeddings powering the Taly agent and semantic KB searchUnited States
ResendTransactional email — onboarding, invites, alerts, dunning, weekly digestUnited States / EU
PaddleBilling & Merchant of Record — checkout, subscriptions, invoicing, global VATEuropean Union (Ireland)
SentryBackend and frontend error monitoring with client-side PII scrubbingEuropean Union (Frankfurt)
UpstashManaged Redis — Bull queues for HRIS sync, background jobs, rate-limit and cacheEuropean Union / United States

This list is kept up to date. We notify customers with a signed DPA of any sub-processor addition or removal at least 30 days in advance.

Report a vulnerability

Found something? Let us know.

We accept vulnerability reports from independent researchers, customers, and anyone who detects a security issue in our infrastructure or products. We commit to: • Acknowledge receipt within 48 business hours. • Coordinate responsible disclosure with you. • Not pursue legal action against researchers acting in good faith.

support@talyzr.com

PGP key available on request. For critical vulnerabilities, include the word «CRITICAL» in the subject line.

Legal documents

Three essential documents for your legal and compliance team.

Does your legal team need more detail?

Write to us to coordinate DPA signing, answer a security questionnaire, or schedule a technical call with our team.