Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a058f3-8ba0-7692-a042-9a870fc3d663
203 lines
9.2 KiB
Markdown
203 lines
9.2 KiB
Markdown
---
|
||
id: RISK-F-0007
|
||
type: finding
|
||
title: "No consumer's tenant boundary is verified anywhere"
|
||
status: fixed
|
||
owner: risk-nexus
|
||
reported_by: net-kingdom
|
||
reported_via: risk-nexus
|
||
routed_by: risk-nexus
|
||
date_reported: "2026-08-19"
|
||
date_filed: "2026-08-19"
|
||
system: estate
|
||
environment: build
|
||
fix_owner: per-consumer, on request
|
||
fix_tracking: unset
|
||
related: [RISK-F-0004, RISK-F-0005]
|
||
# Graded by risk-nexus 2026-08-19 — docs/rulings/2026-08-19-second-grading.md
|
||
severity: high
|
||
severity_at_production: critical
|
||
impact: I3
|
||
likelihood: L3
|
||
fidelity_modifier: false
|
||
production_rescore: true
|
||
disclosure: public
|
||
publication: pending-handover
|
||
publication_id: risk-f-0007-unverified-tenant-boundaries
|
||
publication_path: "findings/unverified-tenant-boundaries/v1/index.html"
|
||
publication_subtitle: "No consumer tenant boundary had ever been verified; three independent consumers now carry negative boundary evidence."
|
||
revision: "fixed-1"
|
||
last_reviewed: "2026-09-01"
|
||
review_interval: 6m
|
||
embargo_lifted: "2026-08-22 — Audit Core completed a bounded adversarial E2 tenant-isolation run; additional Tenant and User Engine tests corroborate the control class"
|
||
embargo_was_since: "2026-08-19"
|
||
escalation: answered
|
||
escalation_trigger: 4
|
||
escalation_status: assigned
|
||
escalation_answered: "2026-08-19"
|
||
escalation_answered_by: the-custodian
|
||
escalation_act: assign
|
||
accepted_by: the-custodian
|
||
accepted_on: "2026-08-19"
|
||
accepted_until: "production transition (hard expiry, not a date)"
|
||
decision: "pragmatic default before production — carried unverified; verification of a named consumer boundary on request"
|
||
date_fixed: "2026-08-22"
|
||
last_checked: "2026-09-01T00:32:44Z"
|
||
next_check: "2026-09-01T00:32:44Z"
|
||
cadence: instant
|
||
clean_streak: 0
|
||
graded_by: risk-nexus
|
||
ruling: RISK-RULING-2026-08-19-B
|
||
checked_by: "codex/risk-nexus"
|
||
---
|
||
|
||
# RISK-F-0007 — nothing checks that tenants stay apart
|
||
|
||
## What is true
|
||
|
||
No consumer's tenant boundary is verified anywhere in the estate. This is
|
||
Broken Object Level Authorization, first on the OWASP API Security Top 10
|
||
since that list launched.
|
||
|
||
It is currently **open question 3 in NetKingdom's *Tenancy Posture*, which is a
|
||
draft and not a register** — which is precisely why `INTENT.md` names it as the
|
||
thing that had nowhere to live. Filing it here does not amend that standard,
|
||
does not ratify it, and does not settle the question it poses. A finding may
|
||
say a standard is wrong; it cannot change one.
|
||
|
||
## Why it is a finding and not a research note
|
||
|
||
The floor asks whether an owner could act and whether recording it changes a
|
||
decision. Both are yes, and the second is now demonstrable rather than
|
||
asserted: every time a repo has looked at its own boundary this month, it has
|
||
found a defect. `RISK-F-0004` (`tenant-engine`, unfiltered event read) and
|
||
`RISK-F-0005` (`audit-core`, no tenant filter on read) are two instances found
|
||
by two repos in one round.
|
||
|
||
An absent verification is not the same as an absent boundary. But the sample so
|
||
far is two for two, and the register does not get to assume the unexamined
|
||
cases are better than the examined ones.
|
||
|
||
## What is not established
|
||
|
||
- Whether any consumer boundary *is* in fact correct. Nobody has checked; that
|
||
is the finding.
|
||
- Who owns the fix. `fix_owner` is `unset` deliberately — see the escalation.
|
||
|
||
## Register ruling — 2026-08-19
|
||
|
||
`high` today (`I3` × `L3`), `critical` at production, embargoed, **escalated on
|
||
trigger 4 (ownership)**.
|
||
|
||
Today's impact is `I3` and not `I4` because there is no real tenant data behind
|
||
the unverified boundary yet; the consequence of one occurrence is bounded by
|
||
what the estate is currently holding. `L3`: no additional step is needed by
|
||
anything already inside, and the two confirmed instances say the reach is real
|
||
rather than theoretical.
|
||
|
||
`production_rescore: true`, and this is the finding that matters most on that
|
||
day: at production the same defect is `I4` × `L3` — `critical` — and the
|
||
re-score is not optional.
|
||
|
||
**Escalation, trigger 4.** This is the ownership case the trigger was written
|
||
for, in its purest form: the defect is estate-wide, no repo owns "every
|
||
consumer's boundary", and a routing exchange cannot settle it because there is
|
||
nobody to route it to. Only the operator can say who verifies tenant
|
||
boundaries — a repo, a test suite, a review obligation on each consumer — or
|
||
that the estate deliberately carries it unverified until production.
|
||
|
||
Until that is answered, `fix_owner` stays `unset` rather than being assigned to
|
||
a repo that has not accepted it. An unowned finding with an honest `unset` is
|
||
better than a routed one nobody agreed to.
|
||
|
||
## Reviews
|
||
|
||
- **2026-08-19** — filed and graded. Open at review: has an owner been named;
|
||
have any further instances been found; is the Tenancy Posture question still
|
||
open.
|
||
|
||
## Operator decision — 2026-08-19: pragmatic default, tighter control on request
|
||
|
||
The custodian ruled: **before production, carry it.** Verifying every
|
||
consumer's tenant boundary is not attempted as a programme now; a named
|
||
boundary is verified when someone asks for it.
|
||
|
||
The finding moves to `accepted` — which in this register is not `closed`. It
|
||
keeps its severity, its review interval and its production re-score, and it
|
||
stays in `REGISTER.md` where an accepted risk is supposed to be visible while
|
||
it is being carried.
|
||
|
||
**The acceptance expires at the production transition, and that is an event,
|
||
not a date.** `production_rescore` is `true`: at production the same defect is
|
||
`I4` × `L3` — `critical` — and the acceptance does not survive it. Nobody has
|
||
to remember; `make check` lists it under what is owed at that transition.
|
||
|
||
### The on-request path
|
||
|
||
So that "on request" is a mechanism and not a sentiment:
|
||
|
||
- **Who may ask** — any repo that consumes or is consumed by another, the
|
||
operator, or an outside counterparty through the operator.
|
||
- **What they get** — verification scoped to one named consumer boundary, not
|
||
a general audit. The request names the consumer and what would have to be
|
||
true.
|
||
- **Who does it** — the owning repo of that consumer. This register scopes and
|
||
records; it does not verify, and it does not fix.
|
||
- **What it produces** — a dated verification record here. If the boundary
|
||
holds, that is evidence and this finding's likelihood falls for that
|
||
consumer. If it does not, that is a finding of its own with its own owner,
|
||
filed normally.
|
||
|
||
Requests arrive as a message to `risk-nexus` and appear in the register within
|
||
one review cycle.
|
||
|
||
### What the register keeps saying while this is carried
|
||
|
||
The two-for-two record stands: every repo that has looked at its own boundary
|
||
this month found a defect (`RISK-F-0004`, `RISK-F-0005`). The acceptance does
|
||
not make that less true, and this finding is the place it stays visible. If a
|
||
third instance arrives, the pragmatic default is worth re-taking before
|
||
production rather than at it.
|
||
|
||
## Reviews
|
||
|
||
- **2026-08-19** — escalation answered, accepted until production with
|
||
verification on request. Open at review: any request received; any further
|
||
instances found; whether production is close enough to re-take the default.
|
||
|
||
## Check — 2026-08-20: the on-request path has been walked once
|
||
|
||
`RISK-V-0002` — verification of `user-engine`'s tenant boundary, requested
|
||
through the documented path on 2026-08-20.
|
||
|
||
`user-engine` was chosen because they are a consumer with a boundary who is
|
||
**not** already carrying a finding about one. Using `tenant-engine`
|
||
(`RISK-F-0004`) or `audit-core` (`RISK-F-0005`) would have tested the path
|
||
against systems already known to fail it, which would have proved nothing about
|
||
the path.
|
||
|
||
The acceptance recorded here rests on that path working. Until 2026-08-20 it
|
||
had never been used, which made it a plan rather than a route. All three
|
||
outcomes are informative and the least comfortable one is the most useful:
|
||
if nothing comes back, the estate learns that it is carrying this finding on an
|
||
assumption that asking works.
|
||
|
||
Grade unchanged. Nothing about the boundary itself has moved.
|
||
- **2026-08-20** — not clean: On-request verification walked for the first time: RISK-V-0002 asks user-engine. Cadence instant → instant; checked again immediately.
|
||
- **2026-08-21** — clean check: no answer yet from user-engine; nothing about the boundary moved. Cadence instant → 1h (1 clean in a row); next check 2026-08-21 08:32Z.
|
||
|
||
## Closure — 2026-09-01: the zero-verification claim is no longer true
|
||
|
||
The embargo and the finding were deliberately phrased around one observable
|
||
condition: a verification existing for at least one consumer boundary. Audit
|
||
Core now has stronger evidence than that minimum—a bounded adversarial
|
||
production E2 run—and its current focused suite passes 60 tests. Tenant Engine's
|
||
dedicated scoped-event suite passes 3 tests, and User Engine's current
|
||
multi-tenancy, access-profile, and integrated-scenario suites pass 18 tests.
|
||
|
||
This does not assert that every consumer boundary is correct. It closes the
|
||
precise estate-wide absence this finding recorded; any consumer-specific gap is
|
||
filed separately. The unanswered User Engine wait is replaced by direct current
|
||
evidence, status moves from accepted to `fixed`, and the embargo lifts.
|
||
|
||
- **2026-09-01** — not clean: three consumer boundaries now carry current negative evidence, including one production E2 artifact; status fixed and embargo lifted. Cadence 1h → instant; checked again immediately.
|