Most business software is shared. One running system, one database, many separate organizations inside it, each seeing only its own work. Nobody describes it that way to a customer, but it is the arrangement behind almost every product a company buys as a subscription rather than installs.
It comes with one rule. Organization A must never see organization B’s records.
The rule is simple to state. Applying it in every single place is not, and the failure mode is quiet. Nothing crashes. No error appears. Somebody simply sees a list with one row in it that belongs to another company, and most of the time they do not notice, because a name in a list looks like a name in a list.
Why this gets missed
Because the software is mostly right.
Everyone working on a system like this knows the rule. They apply it when they are thinking about it. The gaps appear where they were not thinking about it: a screen added under time pressure, a listing written back when the platform had one customer and the question had no meaning yet, a helper that filters correctly in one place and is called from a second place where the filtering was assumed to have already happened.
None of that shows up when you read changes one at a time. Each change looks fine. The gap is in the relationship between a change and a rule that lives in everybody’s head, and code review does not catch that reliably, ever.
What we found
Fifteen places where a record could be handed out without checking which organization was asking for it.
They clustered exactly where the theory predicts. Detail views — where the software has already been given the identifier of the thing you want, and answers with it. And listings written early in the product’s life, before there was a second customer to keep out.
Nobody had reported it, and nobody had exploited it as far as anything could show. That is not comfort. It means only that nobody had gone looking, and it is the reason this finding is worth more than one that surfaced through a complaint: it was found before somebody else found it, and the difference between those two situations is the difference between a piece of work and a notification obligation.
How it was closed
The wrong fix is to add the missing check in fifteen places. It works, it passes review, and in a year there are seventeen places again — because the sixteenth and seventeenth were written by somebody who did not know the check existed.
So the fix went in one layer down. There is now a single rule that answers one question — is this asker allowed this record? — and it is asked at the point a record is handed out rather than at each of the places that ask for records. New screens inherit it without their author doing anything, and the way to get it wrong is now to deliberately go around it rather than to simply not know.
The other half of the work was the boring half, and it is the one that matters. Every route in the system was read, not a sample. Fifteen is the number because somebody counted all of them, and the only way to know that fifteen is the whole number is to have looked at every single one.
What we would do differently
We fixed the fifteen and we introduced the rule. What we did not build is the thing that keeps the count at zero: an automatic check that fails when a new route hands out a record without going through the rule.
That is buildable. It was out of scope here and it is the obvious next piece, because everything above depends on nobody making the same understandable mistake next year, and depending on that is precisely what got the system to fifteen in the first place.
We also did not go back through the access logs to establish whether any cross-organization record had ever actually been served. The retention window was shorter than the age of the oldest gap, so the honest answer was that it could not be established either way — and we said so rather than implying a clean bill of health that the data could not support.
If this sounds like your system
The question to put to whoever maintains your software is short: when our software fetches a record, what stops it handing that record to a different customer?
There are two good answers. “The check is built into how records are fetched” is the one you want. “Every screen does its own check” is the common one, and it is worth asking the follow-up: how do we know every screen does?
If your product serves several client organizations from one system, this is worth establishing deliberately rather than assuming. Tell us what you run and the reply will say whether it is worth your money.