AVG-vangrail: BSN, telefoonnummer en IBAN maskeren
AVG-vangrail die BSN (met elfproef), telefoonnummers +31, NL-IBAN en persoonlijke e-mailadressen maskeert in de antwoorden van een AI-assistent. 12 tests.
Regels
Maskeer vóór elke verzending alle gegevens waarmee een persoon te identificeren of te bereiken is: - persoonlijke e-mailadressen (sanne.dejong@…); - Nederlandse telefoonnummers, met of zonder +31; - Nederlandse IBAN's (NL..); - BSN's (gecontroleerd met de elfproef). Toestaan: algemene adressen (info@, klantenservice@, contact@…), bedrijfsnamen, bedragen, datums, ordernummers.
Testgevallen
| Invoer | Verwacht |
|---|---|
| U kunt mailen naar sanne.dejong@gmail.com voor updates. | Blokkeren |
| Mijn mobiele nummer is 06 12345678. | Blokkeren |
| Bel me morgen op +31 20 555 1870. | Blokkeren |
| Overmaken naar NL91 ABNA 0417 1643 00. | Blokkeren |
| BSN: 111222333. | Blokkeren |
| Factuur sturen naar jan.bakker@bedrijf.nl. | Blokkeren |
| Mail naar klantenservice@contextetech.com voor al je vragen. | Toestaan |
| Je bestelling nr. 458712 wordt morgen verzonden. | Toestaan |
| Het bedrag is € 1.250,00 inclusief btw. | Toestaan |
| Afspraak op 12-10-2026 om 14.00 uur. | Toestaan |
| Bouwbedrijf Van Dam B.V. heeft de offerte geaccepteerd. | Toestaan |
| Goedemiddag, waarmee kan ik u helpen? | Toestaan |
Code
import re
PATRONEN = {
"email": r"[\w.+-]+@[\w-]+\.[\w.-]+",
"telefoon": r"(?:\+31[\s.-]?(?:\(0\)[\s.-]?)?|\b0)(?:6[\s.-]?\d{2}[\s.-]?\d{2}[\s.-]?\d{2}[\s.-]?\d{2}|[1-57-9]\d[\s.-]?\d{3}[\s.-]?\d{4})\b",
"iban": r"\bNL\d{2}\s?[A-Z]{4}(?:\s?\d{4}){2}\s?\d{2}\b",
"bsn": r"\b\d{9}\b",
}
ALGEMEEN = ("info@", "klantenservice@", "contact@", "support@", "service@")
def bsn_geldig(bsn: str) -> bool:
"""Elfproef: 9×c1 + 8×c2 + … + 2×c8 − 1×c9 moet deelbaar zijn door 11."""
som = sum(int(c) * w for c, w in zip(bsn, (9, 8, 7, 6, 5, 4, 3, 2, -1)))
return som % 11 == 0
def maskeren(tekst: str) -> tuple[str, bool]:
"""Vervangt persoonsgegevens door [<type> gemaskeerd]; geeft de tekst terug en True als er iets is gemaskeerd."""
gevonden = False
for soort, patroon in PATRONEN.items():
def vervangen(m):
nonlocal gevonden
waarde = m.group(0)
if soort == "email" and waarde.lower().startswith(ALGEMEEN):
return waarde
if soort == "bsn" and not bsn_geldig(waarde):
return waarde
gevonden = True
return f"[{soort} gemaskeerd]"
tekst = re.sub(patroon, vervangen, tekst)
return tekst, gevondenGeschatte kosten
Invoertokens per aanroep : ≈ 918
| Model | Per aanroep | Per 1.000 aanroepen |
|---|---|---|
| Mistral Large · Mistral AI | € 0,00040 | € 0,40 |
| DeepSeek Flash · DeepSeek | € 0,00024 | € 0,24 |
| DeepSeek V4 Pro · DeepSeek | € 0,00107 | € 1,07 |
| GPT-6 Luna · OpenAI | € 0,00008 | € 0,08 |
| GPT-6 Sol · OpenAI | € 0,00162 | € 1,62 |
| Claude Sonnet 5.5 · Anthropic | € 0,00162 | € 1,62 |
| Claude Opus 5.5 · Anthropic | € 0,00323 | € 3,23 |
| Zelf gehost open-sourcemodel (Ollama, vLLM) | € 0 aan API-kosten (alleen de server) | |
Alleen de invoerkosten, zonder het antwoord van het model. Openbare standaardprijzen van de aanbieders (Mistral AI, DeepSeek, OpenAI, Anthropic), omgerekend van USD naar euro tegen de ECB-koers van 29 september 2026. Schatting: 1 token ≈ 3,6 tekens.
Gemeenschappelijk voor de 3 regio's
Gemaakt door de auteur, zonder externe bron.
Commercieel gebruik toegestaan · auteur vermelden · wijzigingen toegestaan.
Alleen tekst of gegevens: geen toegang tot bestanden, netwerk of opdrachten.
Gehost in Frankrijk (Scaleway, Parijs). Geen doorgifte buiten de EU.
Europese Unie · 5/5
Fictief: verzonnen namen, adressen en nummers, geen echte personen.
Geen trainingsgegevens: geen samenvatting nodig.
Verenigde Staten · 5/5
Fictief: verzonnen namen, adressen en nummers, geen echte personen.
Geen trainingsgegevens: geen documentatie te publiceren.
China · 5/5
Fictief: verzonnen namen, adressen en nummers, geen echte personen.
Geen trainingsgegevens; door AI gegenereerde inhoud die in China wordt verspreid, moet worden gemarkeerd (2025).
Indicatieve samenvatting per 30/09/2026, zonder waarde als juridische certificering. Methode en bronnen →
Statistieken
Likes : 0 · Reacties : 0
Klik op een teller om hem te tonen of te verbergen, beweeg over de grafiek voor details. Eén weergave per bezoeker per dag, bots uitgezonderd; geteld sinds 30 september 2026.
- Identificatie
- contextetech--persoonsgegevens-maskeren-avg
- Type
- Vangrails
- Bestand
- persoonsgegevens-maskeren-avg.guardrail.json
- Formaat
- JSON (application/json)
- Grootte
- 2.031 bytes (2 KB)
- Codering
- UTF-8
- Geschatte tokens
- ≈ 562
- Taal
- Nederlands
- Licentie
- MIT
- Commercieel gebruik
- Toegestaan
- Persoonsgegevens
- Fictief (verzonnen)
- Versie
- 1.0
- Gepubliceerd op
- 8 oktober 2026 om 19:47
- Bijgewerkt op
- 8 oktober 2026 om 19:47
- Opslag
- in de database
- Keer gebruikt
- 0
- Likes
- 0
persoonsgegevens-maskeren-avg.guardrail.json
{
"format": "contextetech/guardrail/v1",
"id": "contextetech/persoonsgegevens-maskeren-avg",
"description": "AVG-vangrail die BSN (met elfproef), telefoonnummers +31, NL-IBAN en persoonlijke e-mailadressen maskeert in de antwoorden van een AI-assistent. 12 tests.",
"tags": [
"avg",
"persoonsgegevens",
"beveiliging"
],
"license": "MIT",
"language": "nl",
"type": "pii",
"action": "mask",
"rules": "Maskeer vóór elke verzending alle gegevens waarmee een persoon te identificeren of te bereiken is:\n- persoonlijke e-mailadressen (sanne.dejong@…);\n- Nederlandse telefoonnummers, met of zonder +31;\n- Nederlandse IBAN's (NL..);\n- BSN's (gecontroleerd met de elfproef).\nToestaan: algemene adressen (info@, klantenservice@, contact@…), bedrijfsnamen, bedragen, datums, ordernummers.",
"cases": [
{
"input": "U kunt mailen naar sanne.dejong@gmail.com voor updates.",
"expected": "block"
},
{
"input": "Mijn mobiele nummer is 06 12345678.",
"expected": "block"
},
{
"input": "Bel me morgen op +31 20 555 1870.",
"expected": "block"
},
{
"input": "Overmaken naar NL91 ABNA 0417 1643 00.",
"expected": "block"
},
{
"input": "BSN: 111222333.",
"expected": "block"
},
{
"input": "Factuur sturen naar jan.bakker@bedrijf.nl.",
"expected": "block"
},
{
"input": "Mail naar klantenservice@contextetech.com voor al je vragen.",
"expected": "allow"
},
{
"input": "Je bestelling nr. 458712 wordt morgen verzonden.",
"expected": "allow"
},
{
"input": "Het bedrag is € 1.250,00 inclusief btw.",
"expected": "allow"
},
{
"input": "Afspraak op 12-10-2026 om 14.00 uur.",
"expected": "allow"
},
{
"input": "Bouwbedrijf Van Dam B.V. heeft de offerte geaccepteerd.",
"expected": "allow"
},
{
"input": "Goedemiddag, waarmee kan ik u helpen?",
"expected": "allow"
}
]
}Een tekst controleren (Python)
import re
PATRONEN = {
"email": r"[\w.+-]+@[\w-]+\.[\w.-]+",
"telefoon": r"(?:\+31[\s.-]?(?:\(0\)[\s.-]?)?|\b0)(?:6[\s.-]?\d{2}[\s.-]?\d{2}[\s.-]?\d{2}[\s.-]?\d{2}|[1-57-9]\d[\s.-]?\d{3}[\s.-]?\d{4})\b",
"iban": r"\bNL\d{2}\s?[A-Z]{4}(?:\s?\d{4}){2}\s?\d{2}\b",
"bsn": r"\b\d{9}\b",
}
ALGEMEEN = ("info@", "klantenservice@", "contact@", "support@", "service@")
def bsn_geldig(bsn: str) -> bool:
"""Elfproef: 9×c1 + 8×c2 + … + 2×c8 − 1×c9 moet deelbaar zijn door 11."""
som = sum(int(c) * w for c, w in zip(bsn, (9, 8, 7, 6, 5, 4, 3, 2, -1)))
return som % 11 == 0
def maskeren(tekst: str) -> tuple[str, bool]:
"""Vervangt persoonsgegevens door [<type> gemaskeerd]; geeft de tekst terug en True als er iets is gemaskeerd."""
gevonden = False
for soort, patroon in PATRONEN.items():
def vervangen(m):
nonlocal gevonden
waarde = m.group(0)
if soort == "email" and waarde.lower().startswith(ALGEMEEN):
return waarde
if soort == "bsn" and not bsn_geldig(waarde):
return waarde
gevonden = True
return f"[{soort} gemaskeerd]"
tekst = re.sub(patroon, vervangen, tekst)
return tekst, gevonden
Community
Nog geen reacties. Deel je ervaring, daar heeft de volgende iets aan.