From 45db85994241f02d474b74f2f4e674ce16c8270b Mon Sep 17 00:00:00 2001 From: tegwick Date: Mon, 17 Aug 2026 15:55:30 +0200 Subject: [PATCH 1/3] Seed INTENT: risk register, regulatory intake, escalation duty Owned by the-custodian alongside policy-nexus, with the duty of deciding what must reach the operator personally. Three things had nowhere to live. Findings landed in whichever document discovered them - the estate's largest known gap is currently open question 3 in an unratified draft, with no owner, severity or date. Disclosure had no mechanism, only publish-now or forget, which is fine in build mode and wrong at production. And regulation was researched at the moment it was needed and never retained. Regulatory intake moves here from policy-nexus T06: deciding what a rule demands of us is a judgement about risk, not an act of publishing. That also leaves policy-nexus doing one thing, which was the point. Two constraints written in deliberately. This repo does not fix - findings route to the repo owning the defect, because a risk service that fixes becomes a second engineering team with no boundary. And it does not block delivery in build mode; if that changes it will be a decision recorded here, not a habit that accretes. The escalation rule is named as unwritten rather than invented. Getting it wrong in either direction fails: escalate everything and the operator becomes the queue, escalate nothing and the register is where serious things go quiet. Co-Authored-By: Claude Opus 5 --- INTENT.md | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 13 ++++++- 2 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 INTENT.md diff --git a/INTENT.md b/INTENT.md new file mode 100644 index 0000000..e1b93f9 --- /dev/null +++ b/INTENT.md @@ -0,0 +1,113 @@ +# INTENT — risk-nexus + +## Why this repo exists + +`risk-nexus` is where the estate holds what it knows is wrong, what might be +wrong, and what the outside world requires of it — with a severity, an owner, +and a date. It serves `risk.coulomb.social`. + +**Owned by `the-custodian`**, alongside `policy-nexus`. One of its duties is +deciding what must reach the operator personally rather than sitting in a +register. + +Before this repo existed, three things had nowhere to live. + +**Findings landed in whichever document was open.** The estate's largest known +gap — that no consumer's tenant boundary is verified anywhere, which is +Broken Object Level Authorization, top of the OWASP API Security Top 10 since +that list launched — is currently open question 3 in an unratified draft +standard. It was found by research, it has no owner, no severity, and no date. +A finding recorded in the document that happened to discover it is a finding +that disappears when that document is superseded. + +**Disclosure had no mechanism.** In build mode the estate publishes everything, +which is right: there are no users to expose. That stops being right at +production, when the same architecture disclosure a consumer must read becomes +a map for an attacker. There is currently no way to hold a finding while it is +fixed and publish it once it is — only publish-now or forget. + +**Regulation was consulted and discarded.** Whether key destruction satisfies +an erasure obligation, whether the estate is an in-scope entity under a given +regime, what a procurement rule requires — each was researched at the moment +someone needed it and never retained. The same question gets asked twice and +the answer silently expires. + +## What it owns + +- **Finding intake.** Security, architecture, operational and compliance + findings, from any source: research, review, incident, external report. +- **Severity and triage.** What this actually risks, how likely, how bad. +- **Remediation tracking** — not remediation. Who owns the fix, what state it + is in, and whether it has stalled. +- **Disclosure timing.** Whether a finding is publishable now, embargoed until + fixed, or permanently restricted; and the record that a delay was deliberate + rather than a document quietly going missing. +- **Regulatory intake**, scoped to regulation bearing on the estate — rules + constraining data it holds, markets it sells into, or obligations it has + taken on. Moved here from `policy-nexus`, because deciding what a rule + demands of us is a judgement about risk, not an act of publishing. +- **The escalation rule.** What must be discussed with the operator personally + rather than recorded and routed. This is the duty `the-custodian` carries as + owner, and the rule itself must be written down rather than exercised by + instinct. + +## What it does not own + +- **Fixing anything.** A finding is routed to the repo that owns the defect, + which fixes it under its own workplan. A risk service that fixes things + becomes a second engineering team with no boundary. +- **Publication.** `policy-nexus` is the publication surface. This repo decides + *whether and when* something is published; it does not host it. +- **Blocking delivery.** In build mode a finding is information, not a gate. + If that changes it will be a deliberate decision recorded here, not a habit + that accretes. +- **Legal advice.** A regulatory record states what a source said and when. + What the estate must therefore do is the owning repo's decision. +- **Deciding what canon says.** Canon is `the-custodian`'s and NetKingdom's. A + finding may say a standard is wrong; it cannot amend one. + +## The failure this repo must avoid + +A risk register nobody reads is worse than no register, because it converts +"we did not know" into "we knew and did nothing" while changing no behaviour. +Two consequences for design: + +- **Findings must expire or escalate.** A finding that has sat untouched past + its review date is itself a finding. Silence is not resolution. +- **The register must be small enough to read.** Recording everything makes + nothing legible. If a finding would not change anyone's decision, it is a + note, not a risk. + +## The escalation duty + +Most findings should be routed and tracked without the operator's attention. +Some must not be. Deciding which is the substance of the oversight `the- +custodian` holds here, and getting it wrong in either direction is a failure: +escalating everything makes the operator the queue, escalating nothing makes +the register a place where serious things go quiet. + +The rule is not yet written. Candidate triggers, to be settled rather than +assumed: anything exposing real tenant data; anything creating a legal or +regulatory obligation; anything requiring spend; anything where two repos +disagree about who owns the fix; and any finding whose remediation has stalled +past a stated interval. + +## Relationship to the rest of the estate + +`risk-nexus` reads from everywhere, decides severity and timing, and routes +work to the repo that owns it. It publishes through `policy-nexus` and never +directly. Like that repo, it is downstream by construction and must not become +a second source of truth — a finding is a claim about a system, and the system +remains authoritative about itself. + +The first content is already waiting: the unverified tenant boundary, the +absent noisy-neighbour characterisation, the missing quality-of-service +vocabulary, and the erasure-versus-audit tension — all currently open questions +in NetKingdom's *Tenancy Posture* standard, which is a draft and not a register. + +## What good looks like + +Nobody is surprised. A gap that was known is recorded with a severity and an +owner, a regulation that applies was found before it was needed, a fix that +stalled was visible while it stalled, and the things that genuinely needed the +operator's judgement reached them without the things that did not. diff --git a/README.md b/README.md index 5acbfd3..f8d8628 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,14 @@ # risk-nexus -A risk management service. \ No newline at end of file +Risk register and regulatory intake for the estate. Serves +`risk.coulomb.social`. Owned by `the-custodian`. + +Holds findings — security, architecture, operational, compliance — with a +severity, an owner and a date; decides whether and when each is published; and +decides which must reach the operator personally rather than sitting in a +register. + +It does not fix things: findings route to the repo that owns the defect. It +does not host: `policy-nexus` is the publication surface. + +- Intent: `INTENT.md` From 97762a4be028e7e999d3b0b583404c5634253c6d Mon Sep 17 00:00:00 2001 From: tegwick Date: Mon, 17 Aug 2026 22:51:31 +0200 Subject: [PATCH 2/3] RISK-F-0001: flex-auth authenticates no caller on the decision surface First finding, and it establishes the record format by being one. Kept minimal on purpose - inventing a schema before there is a second finding to test it against would be designing in the dark. The substance: POST /v1/check and /v1/batch_check authenticate no caller, so any workload with network reach can assert any subject and any tenant and receive an authoritative allow from the estate's authorization oracle. Self-reported by flex-auth during their Tenancy Posture review, and their own note says they did not know they were carrying it. Severity, disclosure and escalation are left unset. Per INTENT this repo owns those and the reporter does not, and filling them in as the routing party would collapse the separation on the first record. Two things stated rather than assumed. Exposure depends on whether a default-deny NetworkPolicy fronts the service; flex-auth did not say, and I did not check, because that would be reporting on a system I do not own. And the disclosure question is genuinely live here - build mode is public-by-default, this is a live authorization bypass, and the controlled-disclosure mechanism this repo anticipates does not exist yet, so the choice today is publish or hold with nothing in between. Three related defects from the same review round are recorded as visible but not filed, since filing them was not asked for. All four were found by repos reading their own code against a ladder within a day of each other, and none was found by monitoring - which is itself a fact worth carrying into triage. Co-Authored-By: Claude Opus 5 --- ...-F-0001-flex-auth-unauthenticated-check.md | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 findings/RISK-F-0001-flex-auth-unauthenticated-check.md diff --git a/findings/RISK-F-0001-flex-auth-unauthenticated-check.md b/findings/RISK-F-0001-flex-auth-unauthenticated-check.md new file mode 100644 index 0000000..3fa88fd --- /dev/null +++ b/findings/RISK-F-0001-flex-auth-unauthenticated-check.md @@ -0,0 +1,103 @@ +--- +id: RISK-F-0001 +type: finding +title: "flex-auth /v1/check authenticates no caller" +status: open +reported_by: flex-auth +reported_via: rapp-postgres +routed_by: rapp-postgres +date_reported: "2026-08-17" +system: flex-auth +environment: production +fix_owner: flex-auth +fix_tracking: FLEX-WP-0015-T02 +# The three fields below are risk-nexus's, not the reporter's. Left unset +# deliberately: the reporter says what is true, this repo says how bad it is +# and who hears about it (INTENT, "What it does not own"). +severity: unset +disclosure: unset +escalation: unset +--- + +# RISK-F-0001 — flex-auth authenticates no caller on the decision surface + +## What is true + +`POST /v1/check` and `POST /v1/batch_check` authenticate no caller. Any +workload with network reach to the ClusterIP Service can assert any subject and +any tenant and receive an authoritative **allow**. + +`flex-auth` is the estate's authorization oracle. Every service that delegates +a decision to it is relying on an answer that anyone able to reach the pod can +obtain for any identity they care to name. + +Self-reported by `flex-auth` as `A0` on their own inbound surface, in their +Tenancy Posture review. Their words: "flex-auth is the estate's authorization +oracle and it trusts its callers completely." + +## How it was found + +Not by a probe, an incident, or an alert. By `flex-auth` assessing themselves +against the Tenancy Posture A ladder during a review they were asked to do — +and their own note says they did not know they were carrying it. + +That provenance matters for triage: nothing was watching for this, and nothing +would have found it. It has presumably been true for as long as the endpoint +has existed. + +## Exposure, as far as the reporter stated it + +- The Service is `ClusterIP`, so reach requires a workload inside the cluster. +- No claim was made that network policy restricts which workloads can reach it, + and this record does not assume one. **If a default-deny NetworkPolicy fronts + the service, that materially changes the exposure and should be verified + rather than inferred** — `flex-auth` did not state it either way, and I have + not checked, because doing so would be reporting on a system I do not own. + +## What makes it worse than a single service's defect + +A false allow from this endpoint is not confined to `flex-auth`. It is the +answer other services act on. `tenant-engine` separately reports that its own +mutations are authorized by `flex-auth` and that direct authority over its rows +would mean "privilege escalation across NetKingdom rather than data tampering +confined to one store". The same reasoning applies to a forged allow. + +## Owner and state + +`flex-auth` owns the fix and has tracked it as `FLEX-WP-0015-T02`, to ship +through the staged-promotion path rather than a direct apply. They classify it +as the only urgent item of their five follow-ups. Nothing is asked of them by +this record beyond what they have already committed to. + +## What this repo is asked to decide + +1. **Severity.** Not the reporter's to set. +2. **Disclosure.** Build mode is currently public-by-default, and this is + precisely the class of finding where that stops being obviously right — a + live authorization bypass in the service every other service trusts. The + controlled-disclosure scheme this repo anticipates does not exist yet, so + the choice today is publish or hold, with no mechanism between them. +3. **Escalation.** Whether this reaches the operator personally. The candidate + triggers in INTENT include "anything exposing real tenant data" — this + exposes the decision that governs access to it, which may or may not be the + same thing, and that judgement is this repo's. + +## Related, reported at the same time and not yet filed + +Three further defects surfaced from the same review round. They are recorded +here so they are visible, not filed as findings, because filing them was not +asked for: + +- `tenant-engine` — `events()` returns the entire event log unfiltered. A live + cross-tenant read at `E2`. +- `audit-core` — read path applies no tenant filter; a credential with + `may_read` can read any tenant's events. Bounded by deployment (`may_read: + false` on the production sender) and not by code. Tracked `AUDIT-WP-0008-T04`. +- `apps-pg` (`railiance-platform`) — no backup configured at all: no + `barmanObjectStore`, no retention policy, `BestEffort` QoS. `R0` there means + no recovery, not merely no erasure policy. + +All four were found the same way, by repos reading their own code against a +ladder, within a day of each other. That is a fact about the estate's +observability worth carrying into triage: **four live defects, none found by +monitoring.** From 38e083ed3de28ae6139aaa83b500e86df7f3e758 Mon Sep 17 00:00:00 2001 From: tegwick Date: Mon, 17 Aug 2026 22:52:37 +0200 Subject: [PATCH 3/3] INTENT: the register is no longer empty, and the first finding tested the deferral Controlled disclosure was deferred to production on the reasoning that build mode has no users to expose. The first finding to arrive is a live authorization bypass in the service every other service trusts, where the choice today is publish or hold with nothing between. The deferral may still be right; it is now a decision with a real case in hand. Co-Authored-By: Claude Opus 5 --- INTENT.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/INTENT.md b/INTENT.md index e1b93f9..04a631e 100644 --- a/INTENT.md +++ b/INTENT.md @@ -100,10 +100,22 @@ directly. Like that repo, it is downstream by construction and must not become a second source of truth — a finding is a claim about a system, and the system remains authoritative about itself. -The first content is already waiting: the unverified tenant boundary, the -absent noisy-neighbour characterisation, the missing quality-of-service -vocabulary, and the erasure-versus-audit tension — all currently open questions -in NetKingdom's *Tenancy Posture* standard, which is a draft and not a register. +The register is no longer empty. `RISK-F-0001` arrived on 2026-08-17: a live +authorization bypass in `flex-auth`, self-reported during a framework review. +Three more defects surfaced in the same round and are recorded inside it as +visible-but-unfiled, pending this repo setting the precedent for what warrants +a record of its own. + +**The first finding already tested the deferral.** Controlled disclosure is +recorded above as deferred to production, on the reasoning that build mode has +no users to expose. `RISK-F-0001` is a live authorization bypass in the service +every other service trusts, and today the choice is publish or hold with +nothing in between. That may still be the right deferral — but it is now a +decision taken with a real case in hand rather than a hypothetical one. + +Also waiting: the unverified tenant boundary, the absent noisy-neighbour +characterisation, and the erasure-versus-audit tension — open questions in +NetKingdom's *Tenancy Posture*, which is a draft and not a register. ## What good looks like