Skip to content

PCI DSS Pregunta 27 — Enmascaramiento de PAN + Restricción de Acceso al PAN Completo

CampoValor
SolicitanteJosé David Álvarez — QSA ControlCase
Comentario QSA (4 sub-preguntas)1) Screenshots con PAN completo (anonimizado). 2) Justificación de negocio por cada pantalla. 3) Listado usuarios/roles con acceso a PAN completo + evidencia. 4) Enmascaramiento con BIN + últimos 4.
Fecha de extracción2026-07-29
Tipo de evidenciaScreenshots UI + código de masking + query de RBAC/RLS + political docs
Estado100% técnico — Masking + endpoint reveal + RolesGuard + rate-limit + auditoría + 10 screenshots UI capturados con Playwright (SEC-026 done). Pending humano: firmas TMPL-015 CEO+Legal solo cuando ocurra primera solicitud PAN reveal + nominación fraud_investigator si aparece caso
Referencias PCI DSSReq 3.4.1, Req 3.4.2, Req 7.2.5, Req 7.2.6, Req 8.3

Resumen ejecutivo: Fintrixs Pay muestra el PAN enmascarado (BIN 6 dígitos + últimos 4 dígitos) por defecto en toda la UI y APIs. La visualización del PAN completo está estrictamente limitada a un rol privilegiado (crypto-admin) que requiere aprobación explícita por operación, auditoría completa vía Vault audit log, y justificación de negocio documentada. Ningún usuario merchant tiene acceso al PAN completo.

Flujo de acceso a PAN según role

Regla dura: solo el rol fraud_investigator puede invocar /reveal. Todos los demás usuarios NUNCA ven el PAN completo — solo Visa ····1234 en cualquier pantalla.


1. Sub-pregunta 4 — Enmascaramiento por defecto (BIN + last4)

1.1 Formato de enmascaramiento estándar

Formato único en toda la plataforma:

411111 ****** **** 1234
└─BIN─┘ └─masked─┘└L4┘
   6 dígitos   6 asteriscos   4 dígitos
  • BIN (Bank Identification Number): primeros 6 dígitos — necesarios para identificar red (Visa/MC/Amex/Diners) e emisor
  • Middle: siempre ****** (6 asteriscos)
  • Last4: últimos 4 dígitos — necesarios para que el cliente reconozca "cuál tarjeta guardé"

Formato conforme a PCI DSS Req 3.4.1 Testing Procedure 3.4.1.a — máximo el BIN + last4 pueden mostrarse.

1.2 Implementación en código

Función central de maskingbackend/apps/tokenization-service/src/tokenization.service.ts:

typescript
export function maskPAN(pan: string): string {
  if (!pan || pan.length < 10) throw new InvalidPANError()
  const bin = pan.substring(0, 6)
  const last4 = pan.substring(pan.length - 4)
  return `${bin} ****** **** ${last4}`
}

Uso obligatorio — SAST rule (Semgrep) que rechaza commits con:

  • console.log(...pan...)
  • logger.info(..., pan) sin passing por maskPAN()
  • Response DTOs que incluyen field pan (deben usar pan_masked)

Ver backend/tools/semgrep-rules/no-plain-pan-in-logs.yml (SEC-023, pendiente).

1.3 Screenshots UI

Screenshots serán capturados al finalizar SEC-016 (persistencia del vault). Ubicación target: ./screenshots/q27-pan-masking/

#PantallaDescripciónArchivo (post-audit)
01Dashboard merchant → Payment methodsCliente ve sus tarjetas guardadas01-merchant-payment-methods.png
02Checkout → confirmación de recurringMuestra tarjeta que se cobrará02-checkout-recurring-confirm.png
03Admin backoffice → transacción detailVer transacción con card_display03-admin-transaction-detail.png
04Email de reciboPDF/HTML con card enmascarado04-email-receipt-masked.png
05Reporte de settlementsExport CSV con card_display05-settlements-report-csv.png

Verificación scriptable:

bash
# Post-SEC-016, ejecutar desde CI:
kubectl -n pci-cde exec deploy/card-vault-service -- \
  psql -U vault_reader -d fintrix_payments \
  -c "SELECT card_display FROM card_vault.stored_cards LIMIT 5;"

# Output esperado:
#           card_display
# --------------------------------
#  411111 ****** **** 1234
#  555555 ****** **** 4444
#  ...

# NO debe aparecer PAN completo en ninguna columna operativa.

2. Sub-pregunta 1 — Pantallas donde se visualiza el PAN completo

2.1 Superficie total (auditoría exhaustiva)

Regla: El PAN completo NUNCA se muestra en ninguna UI. Solo se descifra en runtime del card-vault-service durante:

  1. Autorización de cobro recurring — envío al processor (nunca visualizado por humanos, dura solo ms en RAM del pod)
  2. Investigación forense de fraude — endpoint privilegiado POST /api/v1/vault/reveal (SEC-025) que requiere:
    • Autenticación con AppRole fraud-investigator
    • Justificación de negocio en payload (case_id, reason)
    • Aprobación en 4-eyes principle (2 personas)
    • Genera Vault audit event + Kafka event fintrix.security.pan.revealed
    • Muestra el PAN 60 segundos en UI + auto-clear del clipboard

2.2 Screenshots reales UI (10 pantallas capturadas via Playwright)

Fecha captura: 2026-08-01 Método: Playwright headless chromium contra frontend Vue3 local con seed sintético (0 data prod) Ubicación: docs/security/screenshots/q27-pan-masking/

#PantallaURL evidencia
01Login page (baseline)01-login-page.png
02Dashboard overview02-dashboard-overview.png
03Payments list03-payments-list.png
04Payment detail masked ("Visa ····4242")04-payment-detail-masked.png
05Payment methods ("Vault tokenizado — el PAN nunca toca tu servidor")05-payment-methods-list.png
06Customers list06-customers-list.png
07Customer detail — payment methods07-customer-detail-payment-methods.png
08Subscriptions list08-subscriptions-list.png
09Transactions09-transactions.png
10Refunds report10-refunds-report.png

Script Playwright reproducible: docs/security/screenshots/tools/pw-screenshot-pan-masking.mjs

Cero PAN completo visible en ninguna de las 10 pantallas — solo formatos como Visa ····4242, •••• •••• •••• 1234.

2.3 Justificación de negocio (Req 3.4.1.b)

Única justificación aprobada:

"Investigación forense de fraude o disputa. Necesario para: (a) contacto directo con emisor de la tarjeta para verificar transacción disputada, (b) reporte a autoridades bajo requerimiento legal (Fiscalía / SIC / Superfinanciera), (c) coordinación con procesador de pagos ante ataque de fraude coordinado. En ningún otro escenario operativo se requiere ver el PAN completo."

Aprobación formal firmada por: CEO + Legal + CTO. Documento: docs/pci-dss/policies/PAN-REVEAL-JUSTIFICATION.pdf (pendiente firma).


3. Sub-pregunta 3 — Listado de usuarios y roles con acceso al PAN completo

3.1 Matriz de acceso

RolPuede ver PAN completoMétodo de accesoControles compensatorios
Merchant users (role=merchant_admin)❌ NuncaSolo APIs que retornan card_display (BIN + last4)RLS por merchant_id + response DTOs sin field pan
Merchant staff (role=merchant_operator)❌ NuncaIdemIdem
Fintrixs support (role=platform_support)❌ NuncaSolo dashboards admin con card_displayAuditoría de acceso
Fintrixs fraud investigator (role=fraud_investigator)⚠️ Sí, bajo 4-eyesEndpoint POST /vault/reveal con approval4-eyes + audit + auto-clear 60s + justificación obligatoria
Vault crypto-admin (role=crypto_admin)⚠️ Solo vía Vault transit decrypt (no UI)Vault CLI con MFA + AppRoleVault audit log inmutable
DBA / DevOps❌ Nunca (solo ciphertext)Postgres con vault_reader role — solo columnas cifradasRLS + column-level grants
QSA / auditor externo⚠️ Solo durante on-site audit con supervisiónSesión supervisada por CTO + Security Lead + logsSession recording

3.2 Listado nominativo (post firma)

📄 docs/pci-dss/access-reviews/PAN-COMPLETE-ACCESS-LIST-YYYY-MM.pdf — revisión semestral.

Formato:

FINTRIXS - LISTA DE USUARIOS CON ACCESO AL PAN COMPLETO
Fecha de revisión: 2026-07-29
Próxima revisión: 2027-01-29 (semestral, PCI 7.2.4)

┌────────────────────┬─────────────────┬──────────────────────┬─────────────────────────┐
│ Usuario            │ Rol             │ Justificación        │ Fecha aprobación        │
├────────────────────┼─────────────────┼──────────────────────┼─────────────────────────┤
│ [nombre_1]         │ fraud_investig  │ Lead fraud team      │ 2026-01-15 (CTO firm.)  │
│ [nombre_2]         │ crypto_admin    │ Security Lead        │ 2026-01-15 (CTO firm.)  │
│ [nombre_3]         │ crypto_admin    │ CTO                  │ 2026-01-15 (CEO firm.)  │
└────────────────────┴─────────────────┴──────────────────────┴─────────────────────────┘

Total: 3 personas con acceso privilegiado a PAN completo.
Todos con acuerdo NDA + PCI training completado 2026-07.

Firma CTO: ___________________
Firma Security Lead: ___________________

3.3 Evidencia scriptable (post SEC-025)

Query Vault de policies:

bash
# Listar quién tiene la policy fraud-investigator
vault list identity/entity-alias | \
  xargs -I{} vault read identity/entity-alias/id/{} -format=json | \
  jq 'select(.data.mount_type == "approle") | .data | {name, entity_id}'

vault read identity/group/name/fraud-investigators

Query Postgres RLS:

sql
-- Confirma que NINGÚN rol distinto de crypto-admin puede leer columna pan_ciphertext
SELECT grantee, privilege_type
FROM information_schema.column_privileges
WHERE table_schema = 'card_vault'
  AND table_name = 'stored_cards'
  AND column_name IN ('pan_ciphertext', 'dek_ciphertext');

-- Debe retornar solo: crypto_admin_role (SELECT).

Kubernetes RBAC:

bash
# Confirma que ningún ServiceAccount puede exec en card-vault-service para leer secretos
kubectl -n pci-cde get rolebinding,clusterrolebinding -o json | \
  jq '.items[] | select(.subjects[]?.kind == "ServiceAccount") | 
      {rb: .metadata.name, sa: .subjects[].name, role: .roleRef.name}'

4. Sub-pregunta 2 — Justificación de negocio por pantalla

Referirse a §2.3 arriba — única justificación aprobada es "Investigación forense de fraude o disputa" para el endpoint /vault/reveal.

Ninguna otra pantalla operativa muestra PAN completo. Cero.

Prueba negativa (SAST + audit):

bash
# Ejecutado en cada PR + weekly cron:
semgrep --config backend/tools/semgrep-rules/no-plain-pan-in-frontend.yml \
        frontend/apps/fintrix-dashboard/src/

# Debe retornar 0 findings.

Y query manual del schema del API:

bash
# Buscar cualquier endpoint que retorne `pan` field:
grep -rE "\bpan\s*[:=]" backend/apps/*/src/**/*.dto.ts | \
  grep -v "pan_masked\|pan_display\|pan_fingerprint\|pan_ciphertext"

# Solo debe aparecer en:
#   - tokenization-service/src/dto/tokenize.dto.ts (INPUT, request body)
#   - card-vault-service/src/dto/store.dto.ts (INPUT)
# Nunca en response DTOs.

Anexo — Evidencia real capturada (2026-07-31)

Ver docs/pci-dss/evidence/q27-masking/ para archivos raw.

Frontend deployado con las nuevas páginas

Deploy imagen: registry.digitalocean.com/fintrix/dashboard:sha-7efb2b1e

Bundle Vite en producción (https://app.fintrixspay.com.co/assets/index-BtQRrg1y.js) incluye:

PaymentMethodsPage-CYMR9ZCH.js   (merchant page: masked BIN+last4)
PaymentMethodsPage-DEqWTjCn.js   (chunk secundario)
PanRevealPage-CzLzfWVc.js        (admin 4-eyes reveal)
+ CSS bundles correspondientes

Verificación:

bash
curl -sI https://app.fintrixspay.com.co/dashboard/payment-methods
# HTTP/2 200
# x-frame-options: DENY
# x-content-type-options: nosniff

Rol fraud_investigator creado en producción (auth_db)

Role ID       : de5a0930-c6f2-43b3-8d33-78e8ae558104
Name          : fraud_investigator
Merchant scope: e85adaf7-9b17-45a1-aa28-a56270cac6df (Platform Admin merchant)
Description   : PCI Req 3.4.1: acceso privilegiado a PAN completo bajo 4-eyes
                principle. Solo para investigacion forense de fraude/disputa.
                Audit logged obligatorio.

Permissions (iam_role_permissions):
  - vault:reveal_pan
  - vault:decrypt_forensic
  - audit:read_access_log

Actualmente 0 usuarios asignados a este rol. Cuando el CTO nombre los investigadores forenses (típicamente 1-2 personas), se insertan en iam_core.iam_user_roles.

Endpoint reveal 4-eyes implementado

POST /vault/cards/:cardId/reveal en card-vault-service:

  • Valida requesterId != approverId con timingSafeEqual (previene mismo user aprobándose)
  • Persiste en card_vault.reveal_requests (caseId, justification, requester, approver, timestamp)
  • Emit fintrix.security.pan.revealed a Kafka
  • Retorna PAN + revealRequestId para trazabilidad
  • Frontend: auto-clear del DOM 60s + clipboard wipe 30s

Anotado en código con // nosemgrep + rationale PCI para que Semgrep permita el legítimo return { pan, ... }.


5. Tickets de remediación asociados

TicketDescripciónEstadoFecha objetivo
SEC-023Semgrep rules no-plain-pan (5 rules activas en CI)✅ Implementado2026-07-15
SEC-025Endpoint POST /vault/cards/:id/reveal con RolesGuard + RevealRateLimiter (10/24h) + 4-eyes + audit + Kafka event✅ Implementado + tests2026-08-01
SEC-02610 screenshots UI PAN masking capturados via Playwright headless (login → dashboard → payment detail Visa ····4242 → payment methods vault tokenizado → customer detail → subscriptions → refunds). Ver docs/security/screenshots/q27-pan-masking/README.md✅ Done2026-08-01
SEC-027INV-005-FRAUD_INVESTIGATOR_ROLE.md — registro custodios rol (0 usuarios inicialmente, correcto)✅ Documentado2026-08-01
SEC-028TMPL-015-PAN_REVEAL_JUSTIFICATION.md — formulario CEO+Legal+CISO✅ Template2026-08-01

6. Aprobaciones

RolNombreFirmaFecha
CTO[TO_FILL]
Security Lead[TO_FILL]
CEO (para justificación de negocio del reveal)[TO_FILL]
Legal / Compliance[TO_FILL]
QSA reviewerJosé David Álvarez (ControlCase)

Documentación Confidencial — Solo para uso interno y auditoría PCI DSS