Tema
PCI DSS Pregunta 27 — Enmascaramiento de PAN + Restricción de Acceso al PAN Completo
| Campo | Valor |
|---|---|
| Solicitante | José 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ón | 2026-07-29 |
| Tipo de evidencia | Screenshots UI + código de masking + query de RBAC/RLS + political docs |
| Estado | ✅ 100% 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 DSS | Req 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 masking — backend/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 pormaskPAN()- Response DTOs que incluyen field
pan(deben usarpan_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/
| # | Pantalla | Descripción | Archivo (post-audit) |
|---|---|---|---|
| 01 | Dashboard merchant → Payment methods | Cliente ve sus tarjetas guardadas | 01-merchant-payment-methods.png |
| 02 | Checkout → confirmación de recurring | Muestra tarjeta que se cobrará | 02-checkout-recurring-confirm.png |
| 03 | Admin backoffice → transacción detail | Ver transacción con card_display | 03-admin-transaction-detail.png |
| 04 | Email de recibo | PDF/HTML con card enmascarado | 04-email-receipt-masked.png |
| 05 | Reporte de settlements | Export CSV con card_display | 05-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:
- Autorización de cobro recurring — envío al processor (nunca visualizado por humanos, dura solo ms en RAM del pod)
- 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
- Autenticación con AppRole
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/
| # | Pantalla | URL evidencia |
|---|---|---|
| 01 | Login page (baseline) | 01-login-page.png |
| 02 | Dashboard overview | 02-dashboard-overview.png |
| 03 | Payments list | 03-payments-list.png |
| 04 ⭐ | Payment detail masked ("Visa ····4242") | 04-payment-detail-masked.png |
| 05 ⭐ | Payment methods ("Vault tokenizado — el PAN nunca toca tu servidor") | 05-payment-methods-list.png |
| 06 | Customers list | 06-customers-list.png |
| 07 ⭐ | Customer detail — payment methods | 07-customer-detail-payment-methods.png |
| 08 | Subscriptions list | 08-subscriptions-list.png |
| 09 | Transactions | 09-transactions.png |
| 10 | Refunds report | 10-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
| Rol | Puede ver PAN completo | Método de acceso | Controles compensatorios |
|---|---|---|---|
Merchant users (role=merchant_admin) | ❌ Nunca | Solo APIs que retornan card_display (BIN + last4) | RLS por merchant_id + response DTOs sin field pan |
Merchant staff (role=merchant_operator) | ❌ Nunca | Idem | Idem |
Fintrixs support (role=platform_support) | ❌ Nunca | Solo dashboards admin con card_display | Auditoría de acceso |
Fintrixs fraud investigator (role=fraud_investigator) | ⚠️ Sí, bajo 4-eyes | Endpoint POST /vault/reveal con approval | 4-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 + AppRole | Vault audit log inmutable |
| DBA / DevOps | ❌ Nunca (solo ciphertext) | Postgres con vault_reader role — solo columnas cifradas | RLS + column-level grants |
| QSA / auditor externo | ⚠️ Solo durante on-site audit con supervisión | Sesión supervisada por CTO + Security Lead + logs | Session 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-investigatorsQuery 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 correspondientesVerificación:
bash
curl -sI https://app.fintrixspay.com.co/dashboard/payment-methods
# HTTP/2 200
# x-frame-options: DENY
# x-content-type-options: nosniffRol 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_logActualmente 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 != approverIdcontimingSafeEqual(previene mismo user aprobándose) - Persiste en
card_vault.reveal_requests(caseId, justification, requester, approver, timestamp) - Emit
fintrix.security.pan.revealeda Kafka - Retorna PAN +
revealRequestIdpara 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
| Ticket | Descripción | Estado | Fecha objetivo |
|---|---|---|---|
| SEC-023 | Semgrep rules no-plain-pan (5 rules activas en CI) | ✅ Implementado | 2026-07-15 |
| SEC-025 | Endpoint POST /vault/cards/:id/reveal con RolesGuard + RevealRateLimiter (10/24h) + 4-eyes + audit + Kafka event | ✅ Implementado + tests | 2026-08-01 |
| SEC-026 | 10 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 | ✅ Done | 2026-08-01 |
| SEC-027 | INV-005-FRAUD_INVESTIGATOR_ROLE.md — registro custodios rol (0 usuarios inicialmente, correcto) | ✅ Documentado | 2026-08-01 |
| SEC-028 | TMPL-015-PAN_REVEAL_JUSTIFICATION.md — formulario CEO+Legal+CISO | ✅ Template | 2026-08-01 |
6. Aprobaciones
| Rol | Nombre | Firma | Fecha |
|---|---|---|---|
| CTO | [TO_FILL] | ||
| Security Lead | [TO_FILL] | ||
| CEO (para justificación de negocio del reveal) | [TO_FILL] | ||
| Legal / Compliance | [TO_FILL] | ||
| QSA reviewer | José David Álvarez (ControlCase) |
