BearSignal.ai
ENGINEERING JOURNAL — BEARSIGNAL RESEARCH CORP.SYSTEM: SCANNING 10,000+ LISTED COS
[ 00 / WRITING ]

Visibility Only Goes One Way

[ /engineering ] · 2026-08-02 · 4 min read

We shipped a page that showed anonymous visitors the full list of gray flags. Subscribers paid for that list. It was readable without logging in.

The fix took an afternoon. The law it produced is the part worth writing down, because the bug was not a missing check — it was the absence of a rule that would have made the missing check obvious.

The shape of the failure

Our audience is tiered. Anonymous visitors see a curated showcase. Subscribers see the full case list. Annotation experts see the working queue. Leads see adjudication tooling. Internal staff see everything.

Stated that way it is plainly a hierarchy, and the invariant is plainly monotone: anything visible at a tier must be visible at every tier above it, and nothing may be visible at a tier below the one that owns it.

Nobody had written that down. So each surface was built by asking “who should see this page?” — a question you answer once, correctly, per page. What that question never surfaces is whether the set of things visible at one tier is contained in the set visible at the tier above. An inversion is not a wrong answer to the per-page question. It is a property of the relationship between pages, and per-page review structurally cannot see it.

The list page had been built when the tiering was simpler, and its access rule had not moved with the model. Every individual decision along the way was defensible. The composition was not.

Three ways in, not one

Closing it was more work than expected, because “the page requires login” turns out to be three separate statements.

The page itself was one route. The API it called was another — the data was fetchable without touching the page. And the static artifact was a third: the pre-rendered payload was reachable directly, so the content was legible with no application code in the path at all.

Two of the three had to be closed after the first fix, because the first fix addressed the surface we had noticed. The generalisation is uncomfortable and correct: for any piece of content, enumerate the ways it can be reached before deciding it is protected. The page is one. It is rarely the only one, and it is almost always the one you check.

Making the invariant machine-checkable

An invariant that lives in a document is a suggestion. So the monotonicity property is now something a check can evaluate: fetch each surface as each tier, extract the set of protected entities visible, and assert the containment holds pairwise up the ladder. An inversion — anything visible below its owning tier — is a failure regardless of which page produced it.

Two properties of that check matter more than its existence.

It runs against the deployed site, not the repository. The failure mode was live bytes, not source; a check reading the source would have said the access rule was present and been right about the source and wrong about reality.

And it asserts on the rendered result, not the markup. Content that arrives via a client-side fetch is not in the initial HTML, and a check reading raw markup would report an empty page as compliant. The most reassuring possible reading, from a check that saw nothing at all.

The same sweep turned up a different disclosure path: HTML and CSS comments. Comments do not render, so they feel private. They are in the source of every page, readable by anyone who looks.

We had thousands across the public pages, most of them harmless implementation notes. Some were not — internal reasoning about unresolved issues, written by people who assumed the audience was other engineers.

Comments are now stripped from published artifacts at build time, with the originals archived rather than discarded — the record of what was once exposed is itself worth keeping. And the scanner that enforces it checks for content class, not language: a note about an unresolved incident is a disclosure whether it is written in English or anything else. An earlier version scanned for one language and would have passed the other straight through.

What the law actually says

Visibility is monotone. Anything visible to a tier is visible to every tier above it, and nothing is visible below the tier that owns it. Inversions are defects regardless of intent.

The phrase carrying the weight is regardless of intent. Every inversion we found was produced by a reasonable local decision. Nobody chose to expose the list. The exposure was a property of how correct decisions composed, and only a rule about the composition can catch it.

We did not find this with a test. Someone opened the page in a browser with no session and noticed there was no wall. That has now happened to us more than once — the check that eventually catches the systemic thing is often a person looking at output and finding it implausible. We keep writing the automated checks, and we keep noticing that the first look came from a human.


All figures are system-level results current as of publication date; methodology parameters are intentionally omitted.