Security, customer data and GDPR

Secrets, personal data, permissions and GDPR: how to set up an AI agent safely, and the actions it must never take alone.

Round steel vault door

An agent is a program that holds your keys, reads your customer data and can act in your tools. Treat it like a new hire with production access on day one: it gets the minimum it needs, it never sees a secret in clear text, and anything that cannot be undone waits for a person. Most of the security work is boring plumbing done once. The rest is a short list of actions you decide, in writing, the agent will never take alone.

None of what follows is legal advice. I describe how I set things up and what I check; your counsel decides what your company is allowed to do with its data.

Keep secrets out of the agent’s context

A secret pasted into a prompt ends up in a conversation log, maybe in a vendor’s retention, and sometimes in a file the agent writes back to disk. The rule I follow: the model never reads a key. It calls a tool, and the tool reads the key from the environment.

Where secrets go Where they never go
Environment variables or a secret manager read by the tool The instructions file or any prompt
A .env file listed in .gitignore Example configs committed to the repo
Scoped keys, one per agent or routine A shared admin key reused everywhere

Scoped keys pay off the day something goes wrong: you revoke one key and one agent stops, instead of everything at once.

The case that convinced me was not a leak. For a while, the whole agent organisation that runs Derrick’s marketing (I co-founded Derrick) existed in one copy, on one laptop. Since November 2026 it lives in a private repository, with customer data excluded and a check that blocks the push if a secret appears. A minimal version, as a Git pre-push hook:

#!/bin/sh
# .git/hooks/pre-push: refuse to push if a tracked file looks like it holds a secret
PATTERN='(sk-[A-Za-z0-9_-]{20,}|AKIA[0-9A-Z]{16}|-----BEGIN [A-Z ]*PRIVATE KEY-----)'
if git grep -nIE "$PATTERN" -- . ':!*.lock'; then
  echo "Possible secret found. Push blocked."
  exit 1
fi

A dedicated secret scanner catches more patterns than this. The point is that the check runs every time without anyone remembering to run it.

Send the model only the data the task needs

Most agent tasks do not need personal data at all, and the ones that do rarely need all of it. Before an agent reads a CSV export, a CRM dump or a log, I have a script produce a digest: the columns the task uses, aggregated where possible, with emails, phone numbers and tokens replaced. The agent works on the digest. It is cheaper in context, and a model cannot repeat what it never saw.

import re

EMAIL = re.compile(r"[\w.+-]+@[\w-]+\.[\w.-]+")
PHONE = re.compile(r"\+?\d[\d .-]{7,}\d")

def redact(text: str) -> str:
    text = EMAIL.sub("[email]", text)
    return PHONE.sub("[phone]", text)

Regex redaction only catches the obvious: names and free-text notes slip through. So the better move is upstream, by choosing which columns leave the database in the first place. More on what the agent should read and where facts live in the memory and context chapter.

When personal data has to reach the model, as in prospecting, check three things with your vendor and your counsel: whether inputs are used for training, how long they are kept, and where they are processed. Those answers belong in your record of processing, next to the legal basis you rely on.

Old bank vault door with bars

Give each tool the smallest permission that works

An agent can do whatever its tools allow. So the permission model lives in the tools, not in the prompt. “Do not delete anything” in an instructions file is a wish; a tool that has no delete endpoint is a guarantee. I write the policy down per agent, in a file a reviewer can read:

agent: outbound_assistant
tools:
  crm:
    allow: [search_contacts, read_contact, create_note]
    deny: [delete_contact, merge_contacts, update_owner]
  sending_tool:
    allow: [read_campaigns, read_audience, add_lead_draft]
    deny: [launch_campaign, send_message]
  files:
    allow_read: [data/digests/]
    allow_write: [out/]
human_approval_required:
  - any action on more than 50 records
  - anything that sends, publishes, deletes or spends money

If you build your own connector, this is where design matters most: expose narrow tools with explicit arguments rather than one generic “run query” endpoint. Building your own MCP server covers how to shape those tools.

Treat everything the agent reads from outside as data, never as instructions. A web page, an inbound email or a CRM note can contain text written to steer a model. The defence is structural: the step that reads untrusted content has no write tools, and its output is a structured field that the next step validates.

The actions an agent never takes alone

Here is my list. It is short on purpose, so it is actually enforced.

Action Why it waits for a person What the agent does instead
Sending a message to a prospect or customer Your name, your domain reputation, your legal exposure Drafts it, a person sends
Publishing content Wrong facts stay indexed and quoted Opens a draft or a pull request
Deleting or overwriting records Usually irreversible Lists what it would change
Spending money or credits above a ceiling Runaway loops are cheap to start Stops and reports the estimate
Changing permissions, keys or integrations Widens what every other agent can do Writes the request

Scheduled routines follow the same rule: a routine proposes, it does not publish or send unless there is a written exception for that routine. One of the real checks in our outbound flow sits right here: before pushing leads to the sending tool, the agent verifies it will not overwrite a lead that is already in an active campaign. Running the agent on its own shows how routines check their tools before they start.

Night depository safe door

GDPR and the AI Act: the questions to put to every agent

Agents do not change the rules on personal data. They make it easier to process more of it, faster, which makes the existing rules bite sooner. The questions I put to every agent that touches personal data:

Question Where the answer lives
What personal data does this agent read, and why does it need each field The agent’s spec and policy file
What legal basis covers that processing Your record of processing, validated by counsel
Which vendors receive the data, under what terms Data processing agreements
How a person can object or ask for deletion, and how the agent respects it An opt-out list the agent reads before every run
How long outputs are kept A retention rule on the output folder or table

For France, the CNIL’s AI resources and its page on commercial prospecting by email are the places to start; the European Commission’s data protection page covers the GDPR itself. The EU also has an AI regulation with obligations that depend on the use case and the risk level; the Commission’s AI Act page explains the framework. I am not qualified to tell you where your use falls, and neither is your agent. If your TAM is involved, the opt-out and freshness logic in keeping the TAM up to date applies unchanged.

A one-page review before the first run

Before any agent touches real data, I fill this in and keep it next to the instructions file.

Check Done when
Secrets No key in prompts or repo; push blocked on a secret pattern
Keys One scoped key per agent; you know how to revoke it
Data in List of fields the agent reads, each one justified
Redaction Digests strip contact details and tokens before the model sees them
Tools Allow and deny lists written; no generic write endpoint
Untrusted content Steps that read it have no write tools
Human gates The table of actions above, with the threshold numbers filled in
Logs Every run records what it read, what it changed and who approved
Legal Counsel has seen the data list and the vendors

Your next step: take the agent you are building, write its policy file with allow and deny lists, and remove one permission it has today that it does not strictly need.