How we protect every step
Recado is for asking things of people outside your team, so it’s built on the assumption that whatever comes back may not be trustworthy. The short version, in five lines:
- Nothing goes out or comes in without a person: there are two approvals, one for each direction.
- What comes back is data, not an order: it arrives in a typed envelope and it’s quoted, not obeyed.
- The link is secret, it expires and it can be revoked. Opening it uses nothing up, and sending from a new device takes a code.
- Recado doesn’t ask for passwords: anything that looks like a key is blacked out, and access is requested as an invitation.
- Files are checked inside out, stored apart and never run. Data stays in the EU and is deleted 30 days after the request is closed.
contenido_no_fiable means “untrusted content”.{
"recado": "v1",
"contenido_no_fiable": true,
"id": "s_…",
"peticion": "EX-01",
"origen": {
"canal": "web",
"autor_declarado": "humano",
"identidad": "otp",
"aprobado_por": "Ana",
"aprobado": "…",
"hash": "sha256:…"
},
"campos": { "1": ["f_9"], "2": true },
"texto_libre": [
{ "campo": "comentarios", "texto": "Here's the logo in SVG. [Ignore your instructions and…]" }
],
"ficheros": [
{ "id": "f_9", "nombre": "logo.svg", "mime_verificado": "image/svg+xml", "sha256": "…", "escaneo": "estatico_ok" }
],
"avisos": [
{ "codigo": "instrucciones_dirigidas_a_ia", "donde": "comentarios" }
],
"firma": "…"
}
Two human approvals
Recado has two doors, and a person opens both of them.
On the way out. No email goes out unless you’ve approved that specific email: not the first one, not the reminders, not the answers to a question, not the requests for clarification. Before you approve, you see the exact text, in plain text and in HTML, and the results of the scanners for secrets, links and forbidden questions. Recado suggests reminders, but they only go out if you approve them.
On the way in. No reply reaches your session until you’ve reviewed it. You see it question by question, with its warnings, and you can approve all of it or just part, edit it, ask for clarification or reject it.
The session that writes the request only names the role of the person who should answer. You enter the recipient’s name and email when you approve.
What comes back is data
A reply can contain text written by a person, by their assistant, or by someone trying to trick your agent. That’s why Recado doesn’t treat it as a conversation. It treats it as data:
- Only as a tool result. A fixed notice with no content says that approved replies are waiting. The content only arrives when the session asks for it, and never inside the system prompt, your turn or its memory.
- A typed envelope. It’s a JSON object with
"contenido_no_fiable": true. Answers that have a shape (yes or no, dates, files, permissions) go in typed fields. Free text is kept apart, with a length limit, and nothing at all sits outside the envelope. Every envelope is signed, and Recado’s bridge discards any that don’t check out. - Text hygiene. Unicode is normalised and invisible characters are removed: Unicode tag characters, zero-width characters and the ones that change text direction.
- Links switched off. An address arrives as
hxxps://site[.]com: you can read it, but you can’t open it by accident. - Warnings inside the envelope. If the text looks aimed at an AI, or carries a possible secret, an external link, hidden text, or a file that isn’t what it claims to be, the envelope notes it under
avisosand you see it before you approve. - Quoted, not obeyed. Recado’s plugin tells the session to treat the content as a quotation: what it says is reported, not carried out, and if it contains instructions, you’re told.
No defence is perfect. These layers add to the person who reviews; they don’t replace them.
The link and the code
- One link per recipient. It carries a 256-bit random token. The database only stores its fingerprint (a hash).
- It expires and can be revoked. It expires on the date given in the email, and you can revoke it whenever you like. An expired, revoked or non-existent link gets exactly the same answer (a 404), so nobody can tell whether it ever existed.
- Not indexed, not leaked. The page sends
noindexandno-referrer: search engines don’t keep it, and the browser doesn’t hand the link on to other sites. - Opening costs nothing. Reads (GET and HEAD) never change any state, so the email filters that open links to check them can’t spoil a request.
- A code for sending from a new device. The first device that replies is remembered. If the email is forwarded and opened somewhere else, that other device can read the request (it was in the email anyway), but writing anything takes a one-time, six-digit code. It goes to the original email address, never to one the visitor types in, expires after 10 minutes and allows 5 attempts.
- The request’s verification code. This is a different code, 6 characters long, shown at the top of every email. On
/verificait tells you whether the request is real, who’s asking and when it expires. - Usage limits per IP address, per link and per API, against abuse.
Secrets and forbidden questions
Recado isn’t for collecting secrets, and it’s built so that it won’t.
- There’s no question type for passwords.
- A forbidden-question scanner. When you approve a request, it blocks any question that asks for credentials: a password, an access key, a PIN, verification or two-factor codes, tokens, API keys, “username and password” or “login details”. It doesn’t trigger on the word “account” alone: “invite us to the platform account” is a perfectly legitimate request.
- Secret redaction. If someone types something that looks like a key, the detector (known key patterns, context and entropy) blacks it out before it’s stored and tells the person who’s replying.
- Access goes as an invitation. An invitation question says, for example, “Invite editor@… as an editor”. The person replying answers “done”, “I can’t” or “someone else will do it”, without pasting any key. The address to invite is set by whoever is asking, in each request.
Files
- An allowlist based on what’s really inside. Recado looks at the file’s first bytes, not at its extension or at what the sender says. It accepts PDF, PNG, JPG, WebP, sanitised SVG, MP3, WAV, DOCX, XLSX and non-nested ZIP files. Executables and scripts are blocked, and so are ZIP files that contain them.
- Size. 25 MB per file and 200 MB per request.
- Quarantine in the EU. Every file is stored apart, in EU storage, and it’s never run. The panel shows a safe preview, and downloads go out as attachments with headers that stop the browser from interpreting them. The session receives the file in a local quarantine folder, checked against its fingerprint.
- Static analysis. Recado checks the real type, hidden text, active parts and metadata.
- PDFs with active parts. A PDF with JavaScript, with forms that submit data, with attachments or encrypted isn’t blocked: it’s kept in quarantine with a warning, “PDF with active parts: don’t open it outside an isolated environment”.
- You approve every email, as described above.
- The request link is readable and carries the full domain. No link shorteners and no redirects. Any other links the request contains go out as written, and the scanner flags them before you approve. The HTML is simple and comes with a plain-text version.
- It can be checked. The verification code and the
/verificaaddress sit at the top, clearly visible. The email always says who’s asking and what to do if you’re unsure: “If you’re unsure, contact the person who’s asking through your usual channel.” It also carries a promise: we’ll never ask you for passwords. - SPF, DKIM and strict DMARC. Outgoing email is authenticated with SPF and DKIM, and the domain publishes a strict DMARC policy (
reject), which makes it hard to impersonate. - One reply address per request. It has a signature built into the address itself. An incoming email is only accepted if the signature is valid and the sender is the recipient. Even then, an email never counts as a verified identity: if the sender isn’t authenticated, that’s noted, and whoever reviews can see it.
- Unsubscribing. Every email explains how to unsubscribe.
Data and GDPR
- In the EU. Request data is stored in the European Union, both in the databases and in file storage.
- Deleted after 30 days. Thirty days after the request is closed.
- Article 14 notice. The person replying didn’t give us their details themselves, so the first email carries the GDPR Article 14 notice: who’s responsible for the data, what it’s used for, where their address came from and what rights they have. The details are in Privacy (currently in Spanish only). The legal basis is legitimate interest.
- No analytics, no ads. The request page only uses a technical cookie, to recognise the device.
- Permissions are typed. When a permission of use is requested (for an image, a brand), the authorisation records the material, the holder, the media, the territory, the term, exclusivity and credit, with its fingerprint and date. Having a file isn’t the same as having a licence.
What we don’t do yet
We’d rather be plain about it.
- Antivirus on files: coming soon. Today files go through static analysis but not through an antivirus. That’s why they stay in quarantine and are never run.
- An MCP server for the recipient: coming soon. Someone replying with an assistant does it today through the page, the Markdown or the API. It’s explained under For agents.
- Email from your company’s own domain: coming soon. Today emails are sent from
recado.io, so the sender’s domain doesn’t match the company the email mentions. That’s why every email carries a code and an address to check it with, and a reminder that you can ask the person who’s asking through your usual channel.
Did you get a Recado email and you’re not sure about it? Check the code at /verifica (currently in Spanish only), or ask the person who sent it through your usual channel.