Security

It reads your production database. Here is what stops it doing anything else.

ReplyPen answers support email from your real data. Any good CTO will want to know what happens when the model is wrong, or when a customer email tries to hijack it. This page separates what the kernel and the database engine enforce from what depends on a model behaving, and says what we do about the second part.

Last verified: 3 September 2026 · Operated by ProBackup BV, SOC 2 Type II
The short version

Six things that are true on day one

Every one of these is the default. Loosening any of them is a setting you change per project, later, if the quality earns it.

Nothing is sent without a person

Replies land as a draft in your own inbox. Someone on your team reads it and clicks send. Automatic sending is a switch you can turn on later, per project.

Nothing in your database changes by itself

The model works with read-only database access. Changes go through scripts you approved in advance, and by default each one waits for a human to click confirm.

It only sees the tables and columns you allow

You declare what it may read. Everything else does not exist from its point of view. Your own database enforces this, not a prompt.

Each of your customers sees only their own rows

When a customer asks something, their database view is filtered to their rows before the model reads a single byte. It cannot widen that view, whatever the email says.

Personal data can be masked before it reaches the model

Names, emails and phone numbers in columns you mark are replaced by tokens on the wire. The real values are put back only in the finished draft.

No AI company trains on your data

Two model providers, one in the EU and one in the US, both under business terms that forbid training. The full list, and everything else we keep, is on Where your data goes.

ProBackup BV · audited SOC 2 Type II
Audited

SOC 2 Type II, held by the company that runs ReplyPen

ReplyPen is built and operated by ProBackup BV, a Belgian company whose team has backed up SaaS data for other businesses since 2017, first under the Momentum Tools brand and since 2020 as Pro Backup. That company holds a SOC 2 Type II report, re-examined by an external audit every year, and a public trust center where you can request it, along with the control list, the penetration test summary and the data processing addendum.

  • Encrypted at rest with AES-256, TLS in transit
  • Hosted on Amazon Web Services in Frankfurt, one isolated network, nothing shared with other products
  • Multi-factor authentication and documented approval for every production access
  • Cyber insurance in place
  • Incident response and disaster recovery plans, reviewed yearly
For your CTO

Guaranteed, or merely hard. We keep the two apart.

Some of our controls are enforced by a kernel, a firewall or your database engine. A language model cannot talk its way past them. Others rely on a model or a classifier doing the right thing, and those can fail. Both lists are below, and we say which is which.

Enforced. The model cannot opt out.

What holdsHowEnforced by
A fresh container per run, destroyed afterwards Non-root user, all Linux capabilities dropped, no new privileges, read-only root filesystem, gVisor sandbox between the run and the host kernel. Teardown runs on every exit path, including crashes. Docker, gVisor
Read-only database access The run receives a one-time token for our database proxy. The real connection string never enters the container. The role behind the proxy can only select. PostgreSQL or MySQL, our wire proxy
Only declared tables and columns exist Before each run we mint a short-lived database login and a private set of views over exactly the tables and columns you declared. The base tables answer permission denied. PostgreSQL and MySQL 5.6.0+ are shielded the same way. PostgreSQL or MySQL
One customer, one set of rows Tenant and end customer filters are baked into those views before the run starts, from an identity the host verified. The model never supplies the filter. PostgreSQL or MySQL
No write path through the model Our knowledge repository and your source mirrors are mounted read-only. A write returns a filesystem error. The only write path is an action: a script pinned by its sha256 that you approved, executed with credentials the run never holds. Linux mounts, our action runner
Every outbound connection goes through our gateway A default deny firewall inside the container network namespace. In enforce mode only allowlisted hosts pass. Internal and cloud metadata addresses are refused regardless. Every attempt is logged with host and verdict. Linux netfilter, our gateway
Secrets stay out of the model Your credentials are encrypted with AES-256-GCM at rest and injected into the container environment only. They never appear in command arguments, logs or the model's context. Our host process
Personal data masked by column Columns you mark are tokenized inside the database wire proxy before any byte reaches the container. Real values return only in the delivered draft. Our wire proxy
Autonomy switches live on our side Draft versus send, and human, policy or auto per action, are settings the host checks at the moment of delivery or execution. The model has no way to change them. Our host process
Everything is on record Every command, every network attempt and every action is stored per project and available over the API. Raw content is deleted after 14 days. Postgres, our retention sweep

Probabilistic. A model is still in the loop here, and this is what we bolt on.

Being specific about failure is the point of this section. Read the first column as the risk, the second as the ceiling on the damage, the third as what we add.

What can go wrongWorst case, given the list aboveWhat we add
A customer email, or a web page the model fetches, contains instructions and the model follows them It reads the scoped view it already had and talks to hosts on the allowlist. It cannot reach other tables, other customers, your credentials or an arbitrary server. An input screen on inbound content as defense in depth, never as the only control. A blocked connection produces a visible note on the run, not a silent failure.
The model misreads your data and drafts a wrong answer A wrong draft in your inbox. With auto-send on, a wrong email to a customer. Every draft shows what it checked and where each fact came from. Drafts stay the default until your own edit rate says otherwise. Your corrections feed the next run.
In a customer-facing chat, the model paraphrases how your product is built: a file, a schema, a column list A description of your internals in a chat answer. Not the data itself, which is covered above. A rule in every prompt, a deterministic output guard, a check that no attachment copies your source, and a second model that judges the answer. That last judge can miss. We say so, and every block raises an alert to us.
Personal data outside the marked columns reaches the model The email sender's own details and values in computed or joined columns are not masked. A database we cannot shield is refused rather than used unmasked. Each unmasked path is flagged in the run trace so you can see it. Masking is by declared column and we do not claim it catches free text.
An action on policy mode runs with a wrong parameter A change inside the bounds of the policy you wrote, for example a refund below your cap. The policy is one line of code you wrote, not a model judgement. Caps and human mode are the defaults. Every execution is logged with its parameters.

The strictest setting

This is what a project looks like with every switch closed. You can open any of them later, per project, without a deploy on your side.

Project settings · Security
Automatic sending Off. Drafts only
Actions on your system Off
Internet from the run Off. Only your database host
Every table and column Off. Allowlist, secrets excluded
Raw personal data to the model Off. Masked
Rows of other customers Off. Filtered per customer
Model provider Always on. Google EU or OpenAI USsee where your data goes

The model provider is the one connection that cannot be switched off, because it is the model. Google already runs in the EU; the OpenAI leg moves to OpenAI's EU residency endpoint as a configuration change once our application is approved, which we expect in a matter of weeks. Every other switch here opens something you may want later.

How one customer's question sees one customer's rows

The filter is not a prompt. It is a database view, minted per run, from an identity our host resolved before the model started. The example uses a dental software company with many practices.

Your database

Every table, every row

patients appointments invoices users api_keys audit_log

40 000 patients

Project projection

Only declared tables and columns

patients appointments invoices usersid · name
password_digest
api_keys audit_log

Tenant filter

WHERE practice_id = :scope

Bright Dental Antwerp Smile Clinic Gent Tandarts Peeters Mondzorg Leuven 26 more practices

1 practice · 1 480 patients

Customer filter

AND patient_id = :patient_id

Emma Janssens appointment 3 Sep 14:00 appointment 11 Jun 09:30

1 patient

A database login that can only read stage 4 is what the run logs in with. Asking for stage 1 returns permission denied.

How we attack ourselves

We do not wait for a yearly test. AI agents run break-in attempts against our production, on the real machine, every day: container escape, network egress, credential theft, reaching one project from another. Findings go to a human the same day and are fixed with a retest before they are closed.

We publish the results because we would want to read this about a vendor. In June 2026, during our internal-only pilot, the first full assessment found two critical issues. The network gateway that should filter and log every outbound connection could be bypassed from inside the container, and the container could reach the cloud metadata service and read the machine's credentials. Both were fixed and verified live within four days. The container escape battery held. The same battery runs again on every assessment, and a regression is treated as the headline.

2
critical findings, June 2026
4 days
to fix and verify both
0
container escapes, every run since

Let your own AI check us

Prefer to let your own AI check us? Paste the prompts on Ask your AI into the coding agent that knows your codebase. Every page on this site has a plain-text twin it can read, listed there.

Questions your CTO will ask

Do you need write access to our database?

No. Runs use a read-only role. We also hold a provisioning credential that can create roles and views, used only by our host process and never by a run. Everything we add is our own objects. Drop them and your database is byte for byte what it was.

Do you install anything in our application?

Not for reading. If you want actions, there is an optional library for your framework that executes approved scripts inside your own runtime. Every call to it is signed with a per-project secret and verified with a constant time comparison.

Where does it run?

Amazon Web Services in Frankfurt, one isolated network, production only. Model calls go to Google in the EU and to OpenAI in the US under standard contractual clauses. Nothing else sees email content.

Can our developers see what it did?

Yes. Every command it ran, every network attempt with its verdict, and every action with its parameters are on the run trace and the API. The knowledge it keeps about your product is a git repository you can read and edit.

What access do you need to our mailbox?

Enough to read the inbox and place a draft in it. On Gmail that is one scope, gmail.modify: read, draft and label. It cannot touch account settings or permanently delete mail. It could technically send, which is why send-or-draft is enforced on our host, off by default, and never readable by the model. On Outlook it is the equivalent Graph mail permission. If you would rather grant no OAuth at all, connect a mailbox or alias over IMAP with its own app password.

Our database host cannot allowlist an IP. Now what?

Three options, in the order we suggest them. A read replica on a host that can allowlist. An SSH bastion hop, which we support for MySQL today and for PostgreSQL on request. Or TLS plus a dedicated role whose standing credential is only ever used by our host process: each run gets its own short-lived login minted from it, so the credential you handed over is never inside a run.

How do we look up the sender's account without exposing email addresses?

Declare the email column and mark it as personal data. The lookup by the sender's address still runs inside your database, and the model only ever sees a token where the address would be. The sender wrote their own address in the email, so nothing new is revealed. Tenant matching in a multi-tenant setup comes from a trusted signal we control, a per-tenant mailbox or a signed token, never from anything read out of the thread.

What is left after the 14 days?

The run's timeline: event types, timestamps, and a SHA-256 plus byte count of each scrubbed payload, so you can still prove what ran and when. Network and API logs are deleted outright. Email bodies, query output, drafts and model reasoning are gone. Database backups are encrypted, stay in Frankfurt and roll off after seven days, so nothing scrubbed outlives a backup by more than a week.

What happens if we leave?

Drop our role and schema. Ask us to delete the knowledge repository and we do. Raw email content on our side is gone after 14 days anyway. Nothing was installed and nothing in your system was modified, so there is no migration back.

What do we tell our own customers?

Name us as a processor in your privacy policy, with Google and OpenAI as our sub-processors for the AI step. One sentence usually does it: "Support requests may be processed by ReplyPen (ProBackup BV, Belgium), which uses Google Cloud (EU) and OpenAI (US, under Standard Contractual Clauses) to draft replies; none of them train models on your data." We send the DPA and the sub-processor list in writing.

How do we report a vulnerability?

Write to [email protected]. A person reads it, you get a reply within one business day, and we will tell you what we changed. We do not run a bounty program at this time.

Bring your CTO. We prefer the hard questions up front.

This page describes the system as deployed on the verification date at the top. Where it summarises another company's terms, that company's own policy is the authoritative text. Legal detail lives in the Privacy Policy and Terms of Service.