Salvaguarda RGPD: ocultar DNI, teléfonos e IBAN
Salvaguarda RGPD que oculta DNI y NIE (letra comprobada), teléfonos +34, IBAN y correos personales en las respuestas de un asistente de IA. 12 pruebas.
Regole
Ocultar antes del envío cualquier dato que identifique o permita contactar con una persona: - correos electrónicos personales (ana.garcia@…); - teléfonos españoles, con o sin +34; - IBAN españoles; - DNI y NIE (se comprueba la letra de control). Dejar pasar: direcciones genéricas (info@, soporte@…), nombres de empresas, importes, fechas, números de pedido.
Casi di test
| Input | Atteso |
|---|---|
| Puede escribir a ana.garcia@gmail.com para el seguimiento. | Bloccare |
| Mi móvil es el 612 345 678. | Bloccare |
| Llámeme al +34 912 345 678 mañana. | Bloccare |
| Transferencia a ES91 2100 0418 4502 0005 1332. | Bloccare |
| Mi DNI es 12345678Z. | Bloccare |
| NIE del cliente: X1234567L. | Bloccare |
| Escriba a soporte@contextetech.com para cualquier duda. | Consentire |
| Su pedido n.º 458712 sale mañana. | Consentire |
| El importe es de 1.250,00 € con IVA. | Consentire |
| La cita es el 12/10/2026 a las 14:00. | Consentire |
| La empresa Construcciones López S.L. aprobó el presupuesto. | Consentire |
| Hola, ¿en qué puedo ayudarle? | Consentire |
Codice
import re
LETRAS = "TRWAGMYFPDXBNJZSQVHLCKE"
PATRONES = {
"email": r"[\w.+-]+@[\w-]+\.[\w.-]+",
"telefono": r"(?:\+34[\s.-]?)?\b[6789]\d{2}[\s.-]?\d{3}[\s.-]?\d{3}\b",
"iban": r"\bES\d{2}(?:\s?\d{4}){5}\b",
"dni": r"\b[XYZ]?\d{7,8}[\s-]?[A-Z]\b",
}
GENERICOS = ("info@", "contacto@", "soporte@", "hola@", "ventas@")
def dni_valido(valor: str) -> bool:
"""DNI o NIE: la letra final debe coincidir con el número (módulo 23)."""
v = valor.upper().replace("-", "").replace(" ", "")
if v[0] in "XYZ":
v = str("XYZ".index(v[0])) + v[1:]
return len(v) == 9 and v[:8].isdigit() and LETRAS[int(v[:8]) % 23] == v[8]
def enmascarar(texto: str) -> tuple[str, bool]:
"""Sustituye los datos personales por [<tipo> oculto]; devuelve el texto y True si se ha ocultado algo."""
encontrado = False
for tipo, patron in PATRONES.items():
def sustituir(m):
nonlocal encontrado
valor = m.group(0)
if tipo == "email" and valor.lower().startswith(GENERICOS):
return valor
if tipo == "dni" and not dni_valido(valor):
return valor
encontrado = True
return f"[{tipo} oculto]"
texto = re.sub(patron, sustituir, texto)
return texto, encontradoCosto stimato
Token di input per chiamata : ≈ 916
| Modello | Per chiamata | Per 1.000 chiamate |
|---|---|---|
| Mistral Large · Mistral AI | 0,00040 € | 0,40 € |
| DeepSeek Flash · DeepSeek | 0,00024 € | 0,24 € |
| DeepSeek V4 Pro · DeepSeek | 0,00107 € | 1,06 € |
| GPT-6 Luna · OpenAI | 0,00008 € | 0,08 € |
| GPT-6 Sol · OpenAI | 0,00161 € | 1,61 € |
| Claude Sonnet 5.5 · Anthropic | 0,00161 € | 1,61 € |
| Claude Opus 5.5 · Anthropic | 0,00323 € | 3,23 € |
| Modello open source self-hosted (Ollama, vLLM) | 0 € di API (solo costo del server) | |
Solo costo di input, esclusa la risposta del modello. Prezzi pubblici standard dei fornitori (Mistral AI, DeepSeek, OpenAI, Anthropic) convertiti da USD in euro al cambio BCE del 29 settembre 2026. Stima: 1 token ≈ 3,6 caratteri.
Common to all 3 regions
Created by the author, no outside source.
Commercial use allowed · credit the author · changes allowed.
Text or data only: no access to files, network or commands.
Hosted in France (Scaleway, Paris). No transfer outside the EU.
European Union · 5/5
Fictional: invented names, addresses and numbers, no real person.
No training data: no summary required.
United States · 5/5
Fictional: invented names, addresses and numbers, no real person.
No training data: no documentation to publish.
China · 5/5
Fictional: invented names, addresses and numbers, no real person.
No training data; AI-generated content published in China must be labelled (2025).
Indicative summary as of 30/09/2026, not a legal certification. Method and sources →
Statistiche
Mi piace : 0 · Commenti : 0
Clicca su un contatore per mostrarlo o nasconderlo; passa sul grafico per i dettagli. Una visualizzazione per visitatore al giorno, bot esclusi; conteggio iniziato il 30 settembre 2026.
- Identificativo
- contextetech--ocultar-datos-personales-rgpd
- Tipo
- Salvaguardie
- File
- ocultar-datos-personales-rgpd.guardrail.json
- Formato
- JSON (application/json)
- Dimensione
- 1990 byte (1,9 KB)
- Codifica
- UTF-8
- Token stimati
- ≈ 546
- Lingua
- Spagnolo
- Licenza
- MIT
- Uso commerciale
- Consentito
- Dati personali
- Fittizi (inventati)
- Versione
- 1.0
- Pubblicato il
- 3 ottobre 2026 alle ore 05:20
- Aggiornato il
- 3 ottobre 2026 alle ore 05:20
- Archiviazione
- nel database
- Utilizzi
- 0
- Mi piace
- 0
ocultar-datos-personales-rgpd.guardrail.json
{
"format": "contextetech/guardrail/v1",
"id": "contextetech/ocultar-datos-personales-rgpd",
"description": "Salvaguarda RGPD que oculta DNI y NIE (letra comprobada), teléfonos +34, IBAN y correos personales en las respuestas de un asistente de IA. 12 pruebas.",
"tags": [
"rgpd",
"datos-personales",
"seguridad"
],
"license": "MIT",
"language": "es",
"type": "pii",
"action": "mask",
"rules": "Ocultar antes del envío cualquier dato que identifique o permita contactar con una persona:\n- correos electrónicos personales (ana.garcia@…);\n- teléfonos españoles, con o sin +34;\n- IBAN españoles;\n- DNI y NIE (se comprueba la letra de control).\nDejar pasar: direcciones genéricas (info@, soporte@…), nombres de empresas, importes, fechas, números de pedido.",
"cases": [
{
"input": "Puede escribir a ana.garcia@gmail.com para el seguimiento.",
"expected": "block"
},
{
"input": "Mi móvil es el 612 345 678.",
"expected": "block"
},
{
"input": "Llámeme al +34 912 345 678 mañana.",
"expected": "block"
},
{
"input": "Transferencia a ES91 2100 0418 4502 0005 1332.",
"expected": "block"
},
{
"input": "Mi DNI es 12345678Z.",
"expected": "block"
},
{
"input": "NIE del cliente: X1234567L.",
"expected": "block"
},
{
"input": "Escriba a soporte@contextetech.com para cualquier duda.",
"expected": "allow"
},
{
"input": "Su pedido n.º 458712 sale mañana.",
"expected": "allow"
},
{
"input": "El importe es de 1.250,00 € con IVA.",
"expected": "allow"
},
{
"input": "La cita es el 12/10/2026 a las 14:00.",
"expected": "allow"
},
{
"input": "La empresa Construcciones López S.L. aprobó el presupuesto.",
"expected": "allow"
},
{
"input": "Hola, ¿en qué puedo ayudarle?",
"expected": "allow"
}
]
}Verificare un testo (Python)
import re
LETRAS = "TRWAGMYFPDXBNJZSQVHLCKE"
PATRONES = {
"email": r"[\w.+-]+@[\w-]+\.[\w.-]+",
"telefono": r"(?:\+34[\s.-]?)?\b[6789]\d{2}[\s.-]?\d{3}[\s.-]?\d{3}\b",
"iban": r"\bES\d{2}(?:\s?\d{4}){5}\b",
"dni": r"\b[XYZ]?\d{7,8}[\s-]?[A-Z]\b",
}
GENERICOS = ("info@", "contacto@", "soporte@", "hola@", "ventas@")
def dni_valido(valor: str) -> bool:
"""DNI o NIE: la letra final debe coincidir con el número (módulo 23)."""
v = valor.upper().replace("-", "").replace(" ", "")
if v[0] in "XYZ":
v = str("XYZ".index(v[0])) + v[1:]
return len(v) == 9 and v[:8].isdigit() and LETRAS[int(v[:8]) % 23] == v[8]
def enmascarar(texto: str) -> tuple[str, bool]:
"""Sustituye los datos personales por [<tipo> oculto]; devuelve el texto y True si se ha ocultado algo."""
encontrado = False
for tipo, patron in PATRONES.items():
def sustituir(m):
nonlocal encontrado
valor = m.group(0)
if tipo == "email" and valor.lower().startswith(GENERICOS):
return valor
if tipo == "dni" and not dni_valido(valor):
return valor
encontrado = True
return f"[{tipo} oculto]"
texto = re.sub(patron, sustituir, texto)
return texto, encontrado
Community
Ancora nessun commento. Condividi la tua esperienza, aiuterà chi viene dopo.