AirMemo

v1.0 · 2026-10-18

Security and trust

The long form of the security page: what AirMemo reads, where it sends it, how long it keeps it, who operates what, and the claims we do not make.

Applies to
the hosted service, the hook, and a self-hosted install
Read in
twenty minutes
Short version
The security page

01

What this document is

This is the long form of the security page. That page gives the short answer in eight stations. This document gives the whole answer, clause by clause, and names the thing that enforces each statement: a hook, the control plane, or the database. Where a published document governs the commitment, it is named too: the data processing addendum, the terms, the acceptable use policy, and security.txt.

It covers two deployments. The hosted service is the one at airmemo.com, which we run. A self-hosted install is the same software running on infrastructure you control. Most security documents describe one of those and let the reader assume the other. Clause 3 separates them, and every later clause says who operates what. If you read one clause, read that one.

Version 1.0, dated 18 October 2026. The markdown at api.airmemo.com/security-whitepaper.md is generated from the same source as this page at build time, and the build fails if the two differ. A printed copy and the served file therefore say the same thing.

02

The failure it addresses

An agent acts on whatever is in its context. Two failures follow from that, and they are different problems.

The first is stale context. A team decides something, the decision is written down, and the next agent session still sees the version it saw last week. A study by Meetless gave ten models from three vendors a summary holding six facts about a fabricated product, then superseded all six. Every model returned the stale version and read no files: 0 of 6, with no variance. The study is preliminary. We ran our own version of it, with the protocol and the runs where the product did not help published at /research, rather than quoting only the result that flatters us.

The second is prompt injection: text that arrives through ordinary channels carrying instructions the author of the agent did not give. It is the OWASP LLM01 attack class, and CrowdStrike’s 2026 Global Threat Report observed it across more than 90 organizations (crowdstrike.com/global-threat-report).

The two failures need different mechanisms. Stale context is a version problem: something has to know which statement is in force and put that one in front of the agent. Prompt injection is a provenance problem: text that looks like content must not be allowed to act like an instruction. A product that confuses the two ends up either rewriting the model’s judgment or trusting every string that arrives. AirMemo keeps the first problem in the memo queue and the second at the points where text enters, which is why clause 6 has separate controls for expiry and for scanning.

AirMemo does not fix the model. It does two narrower things. It puts the instruction that is currently in force into the agent’s context before the agent acts, and it keeps a receipt of what the agent was given. Everything in this document is about the security properties of those two things: the path the text travels, the controls on it, who can read it, how long it stays, and what happens when a part fails.

The receipt is the part that makes the rest checkable. It records which memo was given, to which device, at what time, and what the delivered text said. It does not record what the agent did next, because the hook is not in that path and does not see it. A team that wants to know why an agent behaved a certain way can see what it was told; it cannot use the receipt to watch the agent.

03

Two ways to run AirMemo

On a self-hosted install, AirMemo processes nothing. We ship software; you run it.

That sentence decides the rest of this document, so it is worth being literal about it. When an organization self-hosts, the control plane, the database, the hook traffic and every memo live in an environment we do not operate and cannot reach. We issue a licence to the organization that ordered it. The licence file and the support conversation are the only records we hold. Everything else stays with you.

When this document says “we” after this clause, it means the hosted service. Where a self-hosted install changes the answer, the clause says so, in the same paragraph rather than in a footnote.

The split, claim by claim

Who does what, by deployment

QuestionHosted by usSelf-hosted by youWhat we supply
Who operates the systemAirMemoyouthe image, the compose file, and the backup and restore scripts
Who processes the dataus, as processor under the DPAnobody: data never reaches usthe DPA, for the hosted service
SOC 2not held; ours to holdyours, over your environmentthis document as the control description
Penetration testnot commissioned; ours to commissionyoursthreat model, disclosure path, fix timeline
Availabilityour service, with no uptime commitmentyour infrastructure, your SLAreadiness probes, sizing notes, no runtime dependency on us
Residencytwo regions; the EU setting is a claim, not a move todaywherever your database and volume sitthe region table, for hosted
Subprocessorsours, listed in the DPAnone of ours in the runtime paththe hosted list
Retentionsix windows, run by usthe same windows, run in your install; deletion is yoursdocumented defaults and settings
Backupsoursyoursthe dump and restore scripts
Incident detection and noticeours to detect and notifyyours; we notify only if our licence or registry is affectedsecurity.txt and advisories
Patchingoursyoursrelease notes and advisories
AI Actwe are not a model provideryou are the deployerno conformity claim either way
Content filtering and blockingnot offerednot offerednone

The licence is checkable without us. The file is signed, the public key is in the binary, and an operator can verify the signature, read the organization name and the seat ceiling, and watch the software refuse a file that was edited. That is deliberate: a licence check that needed a call to our servers would be a runtime dependency, and a self-hosted install is supposed to have none.

What we hold, and what we cannot do

On a self-hosted install we hold two things: the licence file, which carries the organization name, the seat ceiling, the term and the public key material, and the support conversation you choose to have with us. We do not hold a copy of your database, a backup, a log, a roster, a memo or a receipt. There is no telemetry channel we can turn on from here and no remote console that reaches your install.

That cuts both ways, and the document should say so. We cannot detect an incident in your environment, patch it for you, restore a backup, or produce your audit evidence. We also cannot read your memos, answer a subpoena with your data, or lose it in an incident on our side. The failure modes are yours, and so is the control.

What we can do is supply the things that make your review possible: the image, the compose file, the backup and restore scripts, the certificate generator, the runbook, the threat model behind the twelve controls, and a written answer to a questionnaire. The Helm chart and the Terraform module that the deployment kit describes are not published yet; when they are, this paragraph will name them. Ask for the kit before you sign, run it in a test namespace, and check the claims in this document against what you see.

The licence

A self-hosted deployment runs under a signed licence file, issued to the organization named on the order. The file is verified against a public key compiled into the software, at boot, at enrollment and on a manual re-check. Verification is local. Nothing about the licence is periodic, and it opens no network connection, so an air-gapped install works and a licence cannot be revoked remotely. Expiry is enforced: a file past its end date refuses new enrollments and new sends, keeps reads available for thirty days, then stops the process at boot.

A missing licence file runs the software in community mode, with signup open. A file that is present and invalid stops the process instead of downgrading, so a corrupted or edited file cannot quietly improve an install’s access. A licensed install closes public signup.

The licence is not in the delivery path. A hook does not call us to deliver a memo, and an expired licence does not stop an agent from receiving text until the grace period ends.

04

What the product does and does not do

AirMemo reads the memo queue for one organization and writes text into the context field of an agent platform. It keeps a receipt of what it wrote. That is the whole product surface.

A memo’s life is short and its states are few. It is composed in the portal or arrives through an integration, scanned at entry, stored with an expiry, delivered to the devices that ask for it, and deleted when the expiry passes. A revocation removes it earlier. Each transition writes a row, and the rows are insert-only.

It does not run agents, host a model, or observe what an agent does with the text. It keeps no transcript, holds no model provider key, and makes no request to a model when delivering. The receipt records what the agent was given, not what the agent did next.

One model path exists and is stated because it exists. The learning loop can be pointed at a model to classify the instructions agents were given. It sees a redacted excerpt and its hash, never a transcript, and it is off unless an operator configures it. On a self-hosted install the endpoint is yours to choose, including one inside your network.

Text can also arrive through an integration rather than the compose form. An integration event carries the source system’s identifier, the author it maps to, and the text, and it passes the same scan before it becomes a memo. An integration memo is not signed by the organization’s author key, which is why the signing check is described as a per-org setting rather than a universal guarantee.

There is no content filter and no blocking layer. AirMemo does not decide that a memo is inappropriate and suppress it. It scans for credential patterns and prompt-poisoning payloads at the points where text becomes a memo, and refuses those. That is a narrow check on shape, not a judgment about meaning, and it does not run on the agent’s output.

Customer data is not used to train a model, ours or anyone else’s. There is no analytics package in the hook, no update check, and no separate licence server call, on either deployment.

On the hosted service, support access is metadata only. When an operator searches a roster by employee email or domain, the console returns no message content and no per person address list, and the operator’s own audit rows record the search. On a self-hosted install there is no account for us to search with. If you grant support access, it is an account you create, and you can remove it.

05

Delivery

A memo travels from its author’s browser to the control plane, then from the control plane to the hook on each enrolled machine. The hook writes it into the platform’s context field and records a receipt. The hook talks to one host: the control plane it enrolled with, at the base URL written at enrollment.

The endpoints below are the complete set a hook calls. Learning events appear only while learning is on.

  • /v1/hook/poll
  • /v1/hook/receipt
  • /v1/hook/learning
  • /v1/hook/health

Text is scanned twice, once when a memo is composed and once before delivery. A memo that fails the scan is not stored. When the control plane cannot be reached, the hook waits five seconds by default, then injects what it holds. It never blocks the agent turn, and it never emits a platform block code, so a broken hook cannot stall an agent or hide its own failure. The gap appears in the receipt.

On a self-hosted install this path is the same, with one substitution: the single host is your control plane. A device that cannot reach it behaves exactly as it would against ours, which is to say it fails open on the local queue and records the gap.

Revocation takes effect on the device’s next request, because the control plane checks the device record each time rather than trusting a token until it expires. A device that is revoked while offline stops delivering when it next reaches the control plane, and its local queue is not a way around the check. Traffic between the hook and the control plane is TLS, and on a self-hosted install the certificate is one you issue or buy.

06

The twelve controls

These are properties of the software, so they travel with both deployments. What changes is who operates them: us on the hosted service, you on a self-hosted install. Each entry names the component that enforces it. None of them has a setting that turns it off, with one exception: the signing check is off by default and an organization can turn it on.

  1. 01

    Memo signing

    Portal memos carry an Ed25519 signature from the organization’s author key, and a device refuses one that is present and wrong. The check is a per-org setting, off by default, because an unsigned integration memo is not a wrong one.

    Enforced by hook verification, with the author key held by the control plane.

  2. 02

    Read-only hook

    The hook reads a queue and writes text into the platform’s context field. No shell, no plugin surface, no arbitrary execution.

    Enforced by the hook runtime.

  3. 03

    Scanning where text enters

    Credential patterns and prompt-poisoning payloads are refused at every point where text becomes a memo: the compose form, the API, integration events, and a draft distilled from a correction.

    Enforced by the control plane, at each entry point.

  4. 04

    Expiry, always

    The database refuses a memo that carries no expiry. Revocation removes one before its time.

    Enforced by a column constraint in the database.

  5. 05

    A rate floor no setting can lift

    Thirty portal memos per author per minute, enforced in code, deliberately outside the organization policy table.

    Enforced by the control plane limiter.

  6. 06

    No secrets in the client

    The hook holds its own device key and nothing else.

    Enforced by the hook configuration, which has one secret field.

  7. 07

    Append-only

    Receipts and audit rows accept inserts. The database rejects an update or a delete on either table. An erasure request is the one path that removes rows, and it leaves a proof row behind.

    Enforced by triggers in the database.

  8. 08

    Fail-open, on purpose

    The hook never blocks an agent turn. It waits five seconds by default for the control plane, then injects what it holds.

    Enforced by the hook poller.

  9. 09

    Exit-code discipline

    The hook never emits a platform block code, so a broken hook cannot stall an agent or hide its own failure.

    Enforced by the platform adapters.

  10. 10

    Database TLS, pinned in code

    A connection string cannot turn off TLS outside localhost. A remote URL asking for an unverified connection fails at boot.

    Enforced by the control plane boot guard.

  11. 11

    Account hardening

    Sessions in an httpOnly cookie, CSRF tokens on every state-changing route, scrypt password hashes, TOTP with recovery codes, OIDC single sign-on, SCIM provisioning, and windowed hash anchors over the audit trail.

    Enforced by the portal authentication layer.

  12. 12

    Response headers

    Content type sniffing refused, framing denied, referrer suppressed, HSTS on, and a content security policy that forbids scripts on the public pages.

    Enforced by the control plane response layer.

Three limits belong beside them. Signing covers memos composed in the portal; an integration memo is not signed, and the setting is off by default. Scanning checks the shape of text for credential patterns and known poisoning payloads; a payload that reads like ordinary prose can pass, which is why the hook is read-only and the receipt exists. The rate floor is per author, not a global ceiling, so it limits one account’s burst rather than an organization’s total volume.

The controls are checked in two ways. The test suite exercises the mechanism behind each one: a constraint that refuses a null expiry, a limiter that cannot be raised by policy, a header set that fails a route test, a trigger that rejects an update. And the product runs against itself: our own organization uses the hosted service, and the self-host kit is installed and exercised before a release, including the paths that are supposed to fail. Neither is an audit. Both are how a regression gets caught before a customer finds it.

Two of these are worth reading twice because they are trades, not guarantees. Control 08 fails open: the hook prefers a recorded gap to a stalled agent. Control 07 is append-only: a receipt cannot be edited to say something else, and the only thing that removes one is an erasure request, which leaves proof that it happened.

07

Identity and access

Each enrolled machine holds one key, created at enrollment and written to a private file in the user’s config directory: hook.json, mode 0600 on Unix, and the per user application data folder on Windows, where the folder’s own permissions decide who can read it. The key is a shared secret, not a certificate. The control plane keeps it to check each request.

Revocation is an owner or admin action in the console, and a revoked device stops authenticating at once. There is no in-place rotation: a machine that needs a new key is revoked and enrolled again.

People sign in with a password, with TOTP as a second factor, or through OIDC single sign-on. SCIM provisioning from an identity provider is supported. SAML is not built and is not claimed.

Account hardening covers our own authentication. It does not cover the security of your identity provider. In an OIDC deployment the real risk sits in how that provider authenticates a person and who can administer it, and a compromised identity provider can mint a valid session that our layer will accept. SCIM has the same boundary: provisioning is only as trustworthy as the provider sending it.

There is no support impersonation path in the control plane. An AirMemo employee cannot sign in as a customer. On the hosted service, support reads metadata through the console, and the search writes an audit row in the customer’s own trail. On a self-hosted install we have no account at all unless you create one.

The role model is small on purpose. An owner controls billing, region and organization deletion; an admin controls people, devices and policy; a member authors memos and reads receipts. Administrative actions write audit rows, and a device can be revoked by an owner or an admin without the device’s cooperation.

Who administers a self-hosted install is a decision inside your organization. The software has owner, admin and member roles, and the audit trail records administrative actions. We do not hold a recovery key, a break-glass account, or a way back in.

08

Location and subprocessors

On the hosted service, cloud processing is split. The database runs in US East on Neon. Compute runs in US West on Railway. The two are not co-located, and a request crosses the country to be answered.

Every organization carries a region claim, US by default, selectable as EU by its owner. The claim exists so procurement and auditors can hold us to a stated position. It is not a storage directive, and setting EU moves no data today. When that changes, this clause changes first.

Subprocessors, hosted service only

ServiceRoleWhere
Railwaycompute and hostingUS West
Neonmanaged PostgresUS East
CloudflareCDN and TLS terminationglobal edge
StripepaymentsUS and global
Object storageexports and retention copiesUS for existing buckets
Mail relaytransactional emailper provider

The table is the published position in the DPA. It is not a reading of a deployment: environment values are configuration, and we do not publish them.

In transit, the browser to control plane hop and the control plane to hook hop are both TLS. At rest, the database and compute providers encrypt storage as part of their standard safeguards. We add no key of our own on top, and we make no customer managed key claim. Cloudflare terminates TLS at the edge, so it sees traffic in flight on the way to the origin, as any CDN in that position does. On a self-hosted install, both halves of that sentence are yours: your TLS terminator, your database’s encryption, your key management.

On a self-hosted install, none of the six is in the runtime path. The database is yours, the object store is your volume, the mail relay is the one you configure, and payments do not run. Your data sits wherever your database and volume sit, which is a fact about your infrastructure that only you can state. The DPA’s subprocessor schedule applies to the hosted service.

09

Retention

Six windows govern what is kept. They are defaults in the software, not promises about a particular install.

What is kept, and for how long

DataWindow
Memo contentto its expiry, 7 days by default, then deleted
Receipts and audit rowsinsert-only; read window 7 to 365 days by plan
Pre-authorization rows90 days
Delivery telemetry and refusal events90 days
Intake messages90 days
After offboardingexport for 30 days, then deleted within 30 days

The read window is a plan limit on what you can see. It is not a deletion. Receipts are kept because they are the evidence of what an agent was given, and evidence that can be quietly shortened is not evidence. An erasure request removes the rows it covers, along with memo content, and leaves a proof row recording that the removal happened and when.

One caveat belongs here. A backup taken before a deletion can still contain the deleted row until that backup ages out of the retention schedule. The windows in the table describe the live system, not every copy ever written. For the hosted service the DPA states the backup window; for a self-hosted install your own backup policy decides, which is another reason the dump and restore scripts are part of the kit rather than an afterthought.

On the hosted service we run these jobs, and offboarding follows the two thirty day windows in the table. On a self-hosted install the same jobs run in your deployment, on the same defaults, and deletion is yours: the rows are in your database, and we cannot see or remove them. The dump and restore scripts in the kit are the tool for keeping a copy longer than the windows allow.

10

What we do not claim, for the hosted service

This clause is scoped to the hosted service on purpose. On a self-hosted install the same questions are answered by your environment and your auditor, and the table in clause 3 says which column applies.

SOC 2not held
There is no report yet. We will publish it when it exists, and we do not claim it before then. On a self-hosted install, a SOC 2 report would cover your environment and would be yours to commission.
ISO 27001 and ISO 42001not held
Neither is claimed anywhere on this site, and neither has a date.
EU data processing residencynot offered
The region setting is a record, not a storage directive. Clause 8 says where the bytes actually sit. A self-hosted install stores data wherever you put it, and that location is yours to state.
SAMLnot built
OIDC single sign-on, SCIM, and TOTP are live.
Third-party penetration testnone run
No bounty and no separate disclosure policy. The channel in clause 11 is real and monitored. A penetration test of a self-hosted install is yours to commission.
Signed release image and software bill of materialsnot produced
Installers are checksum published, and the hook binary is hash-pinned in the agent’s own config, so a replaced binary refuses to install without a forced override.
Uptime and recovery commitmentnone in pilot
The terms say so in the availability section. On a self-hosted install, availability and recovery are your infrastructure and your commitment.
AI Act rolestated
AirMemo delivers text your organization wrote. No generated content reaches an agent. One optional classifier assist, operator configured, labels its own low confidence. In a self-hosted install you are the deployer of the system, and we make no conformity claim about your deployment.

If you are buying, the useful questions follow from the list. Ask which of these you need, which your own environment already provides, and which one would stop the purchase. A vendor that cannot answer the last question is guessing at what you need. We will answer it in writing, including when the answer is that a control is not built and is not on a date.

The list is deliberately specific. A document that stays silent about a certification invites the reader to assume it, and an assumption is worse than an absence because nobody can check it.

Two things would change this list. A certification would move a row from not held to held, with the report available under NDA and the scope stated in the same sentence. A decision to offer a control we do not offer today, such as a storage directive behind the EU region setting, would move that row from not offered to offered only when the code does the move. A marketing page that says a control exists before either happens is the failure this clause is designed to prevent.

11

Change, disclosure, contact

This document is versioned. A change to a control, a window, a region or a non-claim bumps the version and the date at the top, and the markdown twin changes on the same day because it is generated from the same source. The build fails if the committed markdown differs from what the page would generate, which is what keeps a printed copy honest.

Security reports go to [email protected], and security.txt states the same channel with an expiry date. We read it, we tell you what we found and when we expect to fix it, and we do not ask you to sign anything before you tell us. Advisories that affect self-hosted installs are published at /security/advisories.

Security questionnaires go to the same address. We answer in writing, and we will tell you when a control is not built rather than leave the row blank. If an answer here contradicts something a buyer was told in a sales conversation, this document is the one we will correct the conversation to match.

An advisory states what is affected, which versions carry the fix, what an operator has to do, and whether the flaw is exploitable without local access. Self-hosted operators get the same advisory as the hosted service, because the code is the same. We publish an advisory for a flaw we fixed even when we believe no install was exposed, so that an operator who patches on a delay can see the reasoning rather than a silence.