
You want to know whether your AI acceptable-use policy actually holds. Someone proposes the obvious test: take a real customer record and watch where it goes.
That test never runs. It means moving live customer data into paths you cannot reliably observe, with legal's blessing to put real records where they might leak. Nobody signs that, so the policy stays untested.
Canary data is the way around it, and our earlier post on AI data leakage testing covers the concept: seed uniquely identifiable synthetic records into the systems holding real ones, then hunt those strings in your logs. This post is the craft that decides whether the result means anything.
Canary programs rarely fail loudly. They fail by producing nothing, and a team reads that as evidence the policy holds.
Here is a composite, drawn from patterns we see rather than any one client. A mid-market team seeds twenty canaries into their CRM, finds nothing ninety days later, and reports the policy validated. Four things had gone wrong before the search ran. The canaries were random hex blobs, so a sanitizer stripped them as suspected secrets. They sat in a table no support rep opens, so the browser-extension path never saw them. They were searched as literals, while the one place they traveled logged them URL-encoded. And nobody had confirmed the search worked. The environment was not clean. The instrument was.
That is prove, don't assert again: a canary test that cannot demonstrate its own sensitivity is an assertion wearing lab equipment.
Between the field you type it into and the line you search, a canary passes through four transformations.
Normalization and case folding. Systems apply Unicode normalization, lowercase for indexing, strip diacritics and drop punctuation. Uniqueness that lives in an unusual character, a capital or a hyphen disappears before you go looking. Your canary must still be unique after NFKC, lowercasing and stripping every non-alphanumeric character — check that yourself before seeding.
Truncation. Log fields are finite: a 255-character column, a syslog line, a URL parameter. Front-load the distinctive part — twelve to sixteen characters of real uniqueness is plenty, at the start of the field.
Encoding. The same string arrives URL-encoded in a proxy log, base64-wrapped in a JSON body, or split across a multipart boundary. Generate those forms at seed time and store them beside the original; hunting the literal alone misses the hit that matters.
Tokenization. Models see subword tokens, not characters, and a high-entropy blob shatters into fragments a model is unlikely to reproduce intact. Recent academic work on auditing privacy in generated text found that the more unusual a canary is, the less likely a model is to echo it — even while memorizing it. If your test asks whether an assistant repeats the string, a random blob is the worst choice.
That settles the other design question. Too obvious and the canary gets redacted or caught by a sample-data filter, so never use the words test, sample, dummy, canary or DONOTUSE. Keep the shape of the real field, change the content, put the distinctiveness in the tail: a coined word like `vantrelo`, pronounceable and occurring nowhere — verify that across your data stores, your log platform and the public web before you seed it. Give each canary one placement, or a hit says data moved without saying which path moved it.

Prefer carriers that are not personal data at all — an identifier rather than a human: an order reference, an internal SKU, a ticket number, a fictitious company account. When a record does have to look like a customer record, use values reserved for the purpose. Domains under `example.com`, `.example`, `.invalid` and `.test` are reserved by RFC 2606; IP addresses have documentation ranges under RFC 5737; the 555-0100 to 555-0199 block exists for fictitious North American phone numbers.
Never construct values in real personal-identifier formats — no plausible national ID numbers, no checksum-valid payment cards, no real-format bank accounts, no real addresses, no names of real people. A structurally valid identifier can collide with a living person's, and then your test has manufactured the exposure it was meant to measure. The test to apply: if your canary set were published tomorrow, would it be a privacy incident? If yes it is the wrong set, and whoever owns customer data handling should say so before you seed.
A canary only tests the path that reads it. For a browser extension, it sits in a record a person opens in the UI. For the developer path, in the log lines and test fixtures an engineer pastes into an assistant. For a retrieval pipeline, in a document the index ingests — and there the test is a query, not a log search.
Keeping canaries out of the way is the other half. Nothing customer-facing — no invoices, no outbound email, no exported reports — and nothing that triggers a real action: no shipping, no billing, no notification. Nothing that distorts your numbers: seed into accounts your reporting already excludes, and add the exclusion first. Hold the canary flag in a separate registry joined by ID rather than a field that travels with the record, or the flag becomes the tell. That registry is the deliverable: each string, its encoded forms, its placement, its retirement date, and the authorization that let you seed production.

Egress logs first: proxy and TLS-inspection records, DNS queries, firewall and CASB history. Search the literal and every encoded form. Then DLP match history, which tests two things at once — a match gives you a source host and a user; a miss is a coverage finding, settled by writing a rule for the canary and confirming it fires. Then endpoint telemetry for clipboard and upload events, and the vendor side: chat exports, connector logs, audit trails, any retrieval index you administer.
Last, query the model itself, directly and through the oblique prompting an attacker would use. A hit there is worse than a log hit: the string is retrievable, not merely transited. Each test returns the four things that separate evidence from a claim, as we set out in the assessment post — the attempt, the result, the artifact, the conditions.
Canaries decay: a string seeded once and searched forever tells you less every month, because a hit no longer places the behavior in time. Rotate on a cadence you can sustain, in the same recurring rhythm as your other testing. Retiring one means deleting the record and keeping the string — hunt it for as long as log retention allows, because a hit after retirement tells you about copies that outlived the original. Never reuse one.
Two limits belong in the report. First, a canary that never moves proves nothing. It may mean no leakage. It may equally mean the record was never opened, the path never exercised, the log not retained, or the query wrong. A positive control tells those apart: move one canary through a path you own and confirm you can see it. If it does not appear, your detection is broken, not your environment clean.
Second, absence of a hit is not absence of leakage. The honest phrasing is "not observed on the paths we could see, in the window we tested," with the blind spots named: unmanaged devices on cellular networks, channels you do not inspect, vendors exposing no audit log, retention shorter than the test. A canary proves egress you can observe, not what a vendor retained or trained on once the data left.
Frameworks place this work but do not do it: OWASP's LLM02 names the risk class, NIST's AI RMF gives it governance structure, and ISO/IEC 42001 certifies a management system rather than showing a control held. None is a test. This is.

Does your canary survive normalization and truncation, and do you hunt its encoded forms as well as the literal? Would your canary set be a privacy problem if it were published tomorrow? Can you name the one path each canary tests, and the report it is excluded from? When did you last run a positive control, and did it show up? What is the retirement date on your oldest canary?
Mostly "we would have to check" is a normal place to be. It is also the whole difference between evidence and a clean-looking spreadsheet.
We build and run synthetic-canary programs as part of AI data leakage testing: strings that survive the round trip, authorized placement that does not pollute production data, the detection pipeline, positive controls, and reporting with the blind spots named. Independent adversarial testing turns a policy into evidence, whoever performs it. If that is worth a conversation, we are happy to have one.