Pakkit.net
← Back to blog

Security

You Can't Protect Data You Haven't Located

Before you can encrypt, mask, or migrate the sensitive data in a system, you have to know exactly where it lives — and that map is rarely obvious, because sensitive values hide in plainly-named fields and innocent-looking ones aren't always what they seem.

  • Security
  • Data Protection
  • Databases
  • Operations

Every conversation about protecting data — encrypt it, mask it, restrict it, migrate it off the old scheme — quietly assumes a prior step that almost nobody has actually done: knowing where the sensitive data is. Not roughly. Exactly. Which tables, which columns, which fields hold secrets versus identifiers versus harmless plaintext. I went looking for that map in a system once, expecting it to be obvious, and found that it wasn’t written down anywhere — and that the obvious guesses were wrong in both directions. You cannot protect what you cannot locate, and locating it is real work.

The map is not obvious, in either direction

The naive approach is to eyeball the field names: password is sensitive, status isn’t, done. That fails two ways, and I hit both:

  • Sensitive data in innocent-looking fields. A value that’s actually a credential or a personal identifier sitting in a column whose name gives no hint. Nothing about the name says “protect me,” so a name-based sweep misses it entirely.
  • Innocent data in scary-looking fields. Columns with names like ...password or ...key that turn out to be config references, not secrets — decoy sensitivity. Treat them as secret and you waste effort encrypting and migrating things that never needed it.

So a field’s name is a hint, not an answer. The only reliable way to know what a field holds is to look at how it’s actually used — and that’s where the real map comes from.

A column named password might be a red herring, and the real secret might be sitting in a column named data. Names lie. Usage doesn’t.

Derive the map from how the data is used

The most trustworthy way I found to locate sensitive data wasn’t reading schemas — it was reading the code that touches the data. The queries tell you the truth: a field that gets run through a decryption function on the way out is, unambiguously, an encrypted secret. A field matched by encrypting the input before comparing is an encrypted lookup key. A field selected and returned as-is is plaintext. The access patterns reveal the classification that the field names conceal, because the code has to actually handle each field correctly, and how it handles them is the evidence.

That gave me a real map: which fields are secrets read back by decrypting, which are keys, which are plaintext, and — importantly — which look sensitive but no code treats as such. Derived from usage, confirmed against the actual schema, flagged where I was inferring rather than certain.

Not all sensitive fields are the same shape

Locating the data also surfaces that “sensitive” isn’t one category with one treatment. In the map I built, the sensitive fields split into meaningfully different shapes that each needed a different handling strategy:

  • Secret values you read back — you can decrypt, re-encrypt, or migrate these in place.
  • Identifier / lookup keys that happen to be sensitive — these are matched by transforming the input, not by reading the stored value, and if they’re part of the primary key you can’t just rewrite them in place at all. Protecting them is a different, harder operation.

If you’d lumped all “sensitive fields” together and applied one plan, you’d have broken the lookup keys. Knowing not just where the sensitive data is but what role each piece plays is what makes a protection or migration plan correct instead of destructive.

The inventory is the foundation, and it has to be confirmed

The uncomfortable truth is that the inventory is the actual first task of any data-protection or data-migration effort, and it’s the one people skip because it’s unglamorous. Skip it and everything downstream is built on a guess: you encrypt the wrong things, miss the right ones, and design a migration that stumbles over a field you didn’t know was special. It’s the same lesson as keeping a map of your environments, pointed at data instead of hosts — you can’t reason about what you can’t enumerate, and the scariest gaps are the ones you didn’t know were there.

And like any map, it’s a claim that has to be checked against reality. A map derived from code is design intent — what the system is supposed to hold. Confirming it against the live data is a separate step, and it’s exactly where the surprises live, which is a story of its own. For now the point stands: protection starts with location. Build the map, derive it from usage rather than names, capture what role each field plays, and flag what you’re inferring. If you’ve built a sensitive-data inventory that changed how a project went, I’d like to hear what it turned up.