Est.

A permission that lived in two places, and only one of them got updated

Authorization logic hiding in two places can silently break outside the happy path.

Staff Writer · · 3 min read
Features · August 4, 2026 · 3 min read · 786 words

There's a specific kind of bug that doesn't feel like a bug at all. It passes QA. The UI works. The API responds correctly. A real tester clicked through the real flow and marked the ticket done. And somewhere underneath all of that, a database constraint is quietly enforcing rules that no longer match what the application believes is true.

That's the one that gets you.

Two Sources of Truth, One Missed Update

Here's the scenario. A team ships a new user-facing permission. The application code gets updated. The middleware checks the right flag. Testing confirms the feature works end-to-end.

What nobody touched was the database layer.

It's a row-level security policy. It's a check constraint, or a stored authorization table that a background job reads from on its own schedule. The specific form doesn't matter much. What matters is that the database has its own opinion about what's allowed, and that opinion wasn't on anyone's deployment checklist.

So now you have a feature that is simultaneously shipped and broken, depending entirely on which path hits it.

Why Testing Didn't Catch It

Here's the uncomfortable part. The testing wasn't sloppy. The testers used the actual UI. They hit the real endpoints. Everything worked because the application layer was, genuinely, correct.

But confirming that the application layer works is only confirming the application layer. That's it. That's the whole claim.

It tells you nothing about what happens when:

  • A reporting tool queries the database directly
  • A background job bypasses the application layer entirely
  • A bulk operation lands on an edge-case data state the happy-path test never touched
  • Someone runs a migration or a manual query in production

In any of those situations, the database-level rule runs on its own. If it was never updated, it enforces the old logic. No error. No alert. Nothing that would obviously surface in normal monitoring. It just quietly does the wrong thing.

The Real Problem: Duplicated Logic With No Reconciliation

The architectural issue isn't that someone made a mistake. It's that the system allowed authorization logic to live in two places with no mechanism keeping them in sync.

When a rule lives in one place, updating it means updating one thing. When the same rule is independently encoded in the application layer and the database layer, updating it means updating two things. And "two things" is exactly where deployment checklists fail quietly, especially when a deadline is close.

I've started calling it the two-lock problem. Two locks on the same door sounds more secure, right up until you realize each one needs a different key.

The audit habit that actually catches this isn't running more manual tests. It's identifying every layer that independently encodes the same rule and then comparing them against each other directly.

That means pulling the current state of all database-level constraints, policies, and authorization tables. Then comparing them against the permission logic in the application code. Then flagging anywhere the two don't agree.

Not glamorous work. It's schema inspection and logic comparison. It's slow and a little tedious. But it's the only way to know whether what the application believes is allowed actually matches what the database will enforce when it runs the check itself.

What This Looks Like in a Real Audit

When I'm reviewing a codebase for authorization correctness, the first question isn't "does the feature work." It's "where does the authorization logic live, and how many places is that."

If the answer is more than one, the follow-up questions are pretty straightforward:

  • What's the mechanism that keeps those two versions in sync?
  • Is that mechanism automated, or does it depend on a human remembering a step?
  • When was each version last updated, and do those timestamps actually line up?

A mismatch in any of those answers is a finding. Not a "worth watching." Not a "potential concern." A finding. The feature works perfectly under normal usage and is silently wrong under any path the application layer didn't happen to exercise during testing.

That gap doesn't show up in a demo. It shows up in a direct database query, or a background process, or a reporting tool running at 2am that nobody thought to include in the test suite.

The Point

A real authorization audit doesn't stop at the layer that's easiest to click through. It inventories every place the rule is encoded, verifies each one independently, and checks whether they agree.

"It worked in the UI" proves the UI path works. That's a true statement. It says nothing about the database. Those are different claims about different systems, and an audit treats them that way.

The most dangerous broken feature is the one that looks completely fine from every angle you thought to check.

More in Features