"We mask Aadhaar numbers" is a claim. An auditor asks how you know, and the usual answer is that the vendor said so. That is not evidence, and the gap between the two is where most masking programmes turn out to be weaker than the slide deck.

This is a practical piece about what to keep, because the controls that make masking auditable are cheap if you design them in and close to impossible to reconstruct afterwards. If you already run masking in production and cannot answer the five questions below from data rather than from memory, that is the gap.

Five questions an auditor will ask

In rough order of how uncomfortable they get.

None of these are answerable by pointing at a masking service. They are answerable by records your own pipeline kept at the time.

The number that makes it auditable

The single most useful thing a masking step can return is a count of how many regions it redacted. Not a success boolean — a count.

A boolean conflates two very different outcomes: "I found an Aadhaar number and covered it" and "I looked, found nothing, and am returning your document unchanged". Both are HTTP 200. Both are "success" from the service's point of view, because nothing went wrong. Only one of them produced a masked document.

A count separates them, and it turns masking from an assertion into a measurement. Our API returns it as a response header:

X-Masked-Count: 2      # two regions redacted, both sides of the card
X-Masked-Count: 0      # nothing found, document returned as supplied

Store that count against the document identifier, and the first two audit questions above become a database query rather than an investigation. Store nothing, and you are relying on the absence of error logs as proof that a thing happened, which is not the same claim at all.

The silent failure that looks like success

A count of zero is the failure mode worth designing around, because it is the one that produces a clean-looking pipeline and an unmasked archive.

It happens for mundane reasons. Glare on a laminated card. A fold running through the digits. A photograph taken at an angle in poor light by a field agent standing in a customer's doorway. A scan where the number sits in the margin that got cropped. OCR is probabilistic, and on real documents rather than clean test files a few per cent will not yield a readable number.

The question is what your pipeline does next, and there are only three honest options.

Pass the original through. Simplest to implement, and it silently recreates the exact problem you deployed masking to solve — with the added harm that the document is now filed as masked. If you do this, your masked archive contains unmasked documents and nothing in your records distinguishes them.

Reject the upload. Defensible, and it fails a customer mid-onboarding because of lighting. Whether that is acceptable depends on how much of your volume it affects, which you should measure before choosing.

Quarantine for manual handling. Where most teams land. It works as long as the quarantine is a named, access-controlled, time-limited location with someone accountable for draining it — and not, as it frequently becomes, the same bucket as everything else with a prefix nobody monitors.

Whichever you choose, the auditable artefact is the same: a record that this document had a count of zero and was routed accordingly.

Testing that redaction is real

This is the test most worth running against any masking tool, including ours, and it takes about thirty seconds.

A PDF has a text layer separate from what is drawn on the page. A tool that "masks" by drawing a black rectangle over the number has changed what a human sees and left the digits fully intact underneath, recoverable by anything that reads the text layer — which includes copy-paste, search indexing, and any downstream system that extracts text.

# Mask a PDF containing a known Aadhaar number, then:
pdftotext masked.pdf - | grep -o '[0-9]\{4\}'

# If the first eight digits of the original number appear
# in that output, the redaction is cosmetic. Real redaction
# removes the pixels and the text, so nothing comes back.

Run the same test on image output by checking that the masked region is a solid fill rather than a semi-transparent overlay. Both failures are invisible on screen and obvious to a script, which is exactly the sort of finding an auditor with a laptop enjoys producing.

Sampling the archive, not the happy path

A masking programme is usually validated against a handful of clean documents chosen by whoever set it up. That tells you the integration works. It tells you nothing about your document population.

Sample from the actual archive instead, and stratify deliberately: the oldest documents, the smallest file sizes, the ones from your least-equipped collection channel, multi-page PDFs, and anything scanned before your current capture app existed. Those strata are where failures concentrate, and a random sample across the whole corpus will under-represent them because most of your volume is recent and clean.

A hundred documents drawn that way, checked by hand, will tell you more about your real masking rate than fifty thousand processed without inspection. And the exercise produces a written record of a control test, which is itself the artefact an auditor is looking for.

Where the originals are, and why that ends the conversation

The fifth question on the list above is the one that tends to close an audit meeting, so it is worth answering before someone else asks it.

Masking produces a new document. It does not, by itself, do anything about the one it was derived from. Whether the original survives is a property of your pipeline, not of the masking tool, and it is decided by a handful of implementation details that are easy to get wrong without noticing.

The upload buffer. If the unmasked file is written to disk or object storage before being passed to masking, that write is your exposure, and its lifetime is however long your cleanup job takes — which in practice is however long since anyone checked that the cleanup job still runs. Masking in the request path, before the first persist, is the only design where this question has a clean answer.

Queue payloads and retries. Asynchronous designs frequently put the document itself on a queue. Those messages persist, sometimes for days on a dead-letter queue after a failure, and they are rarely covered by the retention policy that governs the document store. A dead-letter queue holding unmasked KYC documents from six months of intermittent failures is a common and genuinely unpleasant finding.

Backups and snapshots. If unmasked originals were ever persisted, they are in your backups, and they will outlive the masking programme by the length of your backup retention. This one cannot be fixed retroactively in any satisfying way, which is the strongest practical argument for masking at intake rather than after: it is the only approach where there is nothing in the backups to worry about.

Logs and error reporting. An exception handler that attaches the request body for debugging will cheerfully write an Aadhaar document into your logging platform, where it is searchable by a much wider group of people than can open the document store, and where retention is usually set by the logging vendor's default rather than by your policy.

The honest position, if any of these apply to you, is to say so and scope the remediation, rather than to answer the question as though masking implied deletion. Auditors are considerably more comfortable with a known gap and a dated plan than with an assurance that does not survive the follow-up question.

What a defensible masking log contains

Per document, at the time of processing, and joinable to your document inventory:

FieldWhy it is there
Document identifierJoins the log to the file and to the customer record
TimestampEstablishes masking happened before the document was persisted, not after
Regions redactedThe measurement; zero is a finding, not a pass
Outcome routingStored, rejected or quarantined — and if quarantined, when it was drained
Tool and versionLets you scope an incident if a detection bug is found later
Source channelMakes failure clustering visible by capture app, branch or agent

Note what is deliberately absent: the Aadhaar number, in any form, hashed or otherwise. A masking log that records the value it redacted is a database of Aadhaar numbers with extra steps, and it tends to be less well protected than the document store because nobody thinks of it as sensitive.

Note also what the timestamp is doing. It is the field that distinguishes "we mask at intake" from "we ran a masking job over the archive last quarter", and it is the difference an auditor cares about most, because only one of those means unmasked copies never existed downstream.

Questions worth asking a vendor

Including us. If a supplier cannot answer these crisply, that is information.

The five tests we think are worth running against any masking tool, set out in more detail, are in how to choose Aadhaar masking software.

This describes control design and evidence, not legal or audit advice. What your regulator or internal audit function will accept depends on your licence and their methodology, and is worth confirming with them rather than with a vendor.

Masking you can evidence. Every response carries X-Masked-Count, so your pipeline can record per document how many regions were redacted — and branch on zero rather than filing an unmasked document as masked. Nothing is retained.

Get API Access