diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bf80165 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.repo-manager/ diff --git a/.repo-classification.yaml b/.repo-classification.yaml new file mode 100644 index 0000000..75c9590 --- /dev/null +++ b/.repo-classification.yaml @@ -0,0 +1,29 @@ +repo_classification: + standard: Repo Classification Standard + version: "1.0" + classified_at: "2026-08-21" + classified_by: codex + category: tooling + domain: infotech + secondary_domains: [] + capability_tags: + - access-control + - evidence + - traceability + - compliance + - risk + - audit + - observability + - operations + business_stake: + - technology + - operations + - legal + - automation + business_mechanics: + - control + - operation + - adaptation + notes: >- + NetKingdom offensive-security tooling that produces independently operated, + authorization-bound adversarial evidence and routes findings to risk-nexus. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..b7f2a4a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,123 @@ +# whitehat-security — Agent instructions + +## Repository identity + +**Purpose:** Authorization-bound offensive-security tooling that produces +adversarial evidence about security claims and routes findings to the +responsible party. + +**Owner:** NetKingdom +**Domain:** infotech +**Repo slug:** `whitehat-security` +**Topic ID:** `cee7bedf-2b48-46ef-8601-006474f2ad7a` +**Workplan prefix:** `WHITEHAT-WP-` + +## Orient before working + +1. Read `INTENT.md` and `SCOPE.md`. +2. Read `docs/rules-of-engagement.md` before designing or executing probes. +3. Read `.custodian-brief.md` when present and scan `workplans/`. +4. Check the repository inbox: + + `curl -s "http://127.0.0.1:8000/messages/?to_agent=whitehat-security&unread_only=true"` + +5. Check the worktree before editing; preserve unrelated user changes. + +## Non-negotiable safety boundary + +- The rules of engagement are pending personal operator approval. Until they + are approved, perform only documentation work and non-networked fixture + design. Send no packets to a target. +- Even after approval, no live run starts without a dated engagement record + naming authorization, target owner, exact scope, window, technique, + credentials, rate/concurrency ceiling, abort contact and finding destination. +- Never broaden scope after discovery. Record an adjacent system and stop. +- Never collect real tenant row values or credentials as evidence. +- Never use superuser, owner or `BYPASSRLS` privilege for convenience. +- Never perform destructive, persistence, lateral-movement or denial-of-service + activity outside an explicitly authorized technique and window. +- A pass means only that the attempted attacks did not work. Every probe must + first fail against a known-bad fixture. +- This repository finds and reports; it does not fix targets or assign severity. + +## State Hub integration + +State Hub is the coordination index; repository files remain authoritative. + +| Context | URL | +| --- | --- | +| Local workstation | `http://127.0.0.1:8000` | +| Remote tunnel | `http://127.0.0.1:18000` | +| Optional edge relay | `http://127.0.0.1:18080` | + +Use `/state/health` for health checks. After changing workplan files, run: + +`statehub fix-consistency` + +If the command reports C-06/C-11 because this host is not the identifier +registrar, do not set `STATEHUB_REGISTRAR` manually. Commit and push the +file-backed work, then use the scoped fallback once: + +`uv run --project ~/repo-manager rmgr registrar-reconcile --path . --confirm-primary --push` + +At session close, ensure file task statuses reflect reality and record +significant progress in State Hub. Actionable residuals from a finished +workplan must become live work records rather than remaining only in prose. + +## Credential routing + +Before requesting credentials, API keys, SSH access or database passwords: + +`warden route find "" --json` + +`ops-warden` issues SSH certificates only. Other secret material belongs to the +custody route returned by `warden`. Never put credentials in Git, State Hub, +workplans, logs, evidence or chat. + +## Workplan convention + +Workplans live at `workplans/WHITEHAT-WP-NNNN-.md`. Finished plans may +move to +`workplans/archived/YYMMDD-WHITEHAT-WP-NNNN-.md` without changing their +frontmatter ID. + +Required frontmatter: + +```yaml +--- +id: WHITEHAT-WP-NNNN +type: workplan +title: "..." +domain: infotech +repo: whitehat-security +status: proposed | ready | active | blocked | backlog | finished | archived +owner: ... +topic_slug: ... +created: "YYYY-MM-DD" +updated: "YYYY-MM-DD" +state_hub_workstream_id: "" # written by reconciliation; do not edit +--- +``` + +Each task uses one machine-readable block: + +````markdown +```task +id: WHITEHAT-WP-NNNN-T01 +status: wait | todo | progress | done | cancel +priority: high | medium | low +state_hub_task_id: "" # written by reconciliation; do not edit +``` +```` + +Use `proposed` for drafts, `ready` after review, `active` once work has begun, +and `finished` only when all required work is complete or residuals have live +owners. Task progression is `todo` → `progress` → `done`; `wait` is for work +that cannot currently proceed and `cancel` is terminal. + +Small, low-risk work completed directly may use +`workplans/ADHOC-YYYY-MM-DD.md`. Anything requiring analysis, approval, +dependencies or multiple phases needs a normal workplan. + + + diff --git a/INTENT.md b/INTENT.md new file mode 100644 index 0000000..b6b281a --- /dev/null +++ b/INTENT.md @@ -0,0 +1,193 @@ +# INTENT — whitehat-security + +## Why this repo exists + +`whitehat-security` is **NetKingdom's offensive security facility**. It attacks +IT infrastructure and surfaces we choose to point it at — our own estate among +them — and reports what it finds to whoever is responsible for fixing it. + +The discipline is offensive because offence is how you find out. A control is +believed until someone tries it. Everything else in the estate's security work +describes what should be true; this repo establishes what is. + +It was seeded to close a specific gap, which remains its first job. NetKingdom's *Tenancy Posture* standard +splits evidence into two kinds: **mechanical** — a structural assertion a +machine can make, which belongs in each repo's own CI — and **adversarial** — +a semantic claim that requires setting up hostile conditions and observing what +happens. Every repo can produce the first. **No repo can honestly produce the +second about itself**, and the framework's most severe open question has been +sitting unowned for exactly that reason: who verifies that a consumer's tenant +boundary actually holds. + +Two repos were asked and both correctly declined, on the grounds that a service +which grows fleet responsibilities because it happened to be nearby is how +boundaries erode. They were right. The work needed a home of its own. + +## Owner: NetKingdom + +`whitehat-security` is a NetKingdom capability, alongside the IAM Profile, +SSO/MFA and the canonical security architecture. Offensive security is security +work, and it belongs with the repo that owns security. + +**Separation of concerns still applies, one level down.** A repo testing its own +boundary grades its own homework. `rapp-postgres` wrote fifteen adversarial +probes against its own isolation model and found four real defects in its own +provisioning SQL — good work, and still the author checking their own work. The +probes most worth having are the ones an author would not think to write, +because the assumption that produced the defect produces the blind spot. So: + +- This facility does not take a repo's declared posture as true. It tests it. +- It does not decide how bad its own findings are. Severity and disclosure are + `risk-nexus`'s, which is `the-custodian`'s, not NetKingdom's. + +**One residual tension, recorded rather than argued away.** NetKingdom owns the +Tenancy Posture framework *and* this facility. When whitehat tests conformance +to that framework, NetKingdom is assessing NetKingdom. The mitigation is the +routing above: findings leave for `risk-nexus` under separate ownership rather +than being resolved inside NetKingdom. That is proportionate, not perfect, and +worth revisiting if conformance findings ever start getting quietly closed. + +## What it owns + +- **Adversarial evidence artifacts.** The tests that produce the evidence the + Tenancy Posture ladders require but no repo can self-certify: + cross-tenant read and write attempts (E2), row-level-security conformance + under attack (E3), per-tenant credential confinement (E4), + noisy-neighbour characterisation (P1/P2), erasure verification (R4). +- **The attacker model.** What an adversary is assumed to hold at each level — + a leaked runtime credential, SQL execution, a compromised process — written + down, so a probe can be judged against a threat rather than against taste. +- **Cadence.** How often each probe runs. This is not a scheduling detail: for + any control whose guarantee is *detection rather than prevention*, the + interval between runs **is** the exposure window. `rapp-postgres` ADR-0003 + says so explicitly and leaves the number to be set here. +- **Differential testing between tenant contexts.** Running the same request as + two tenants and comparing responses is the mechanically reproducible core of + cross-tenant testing, and it is this repo's principal technique. +- **Target selection and authorization.** Which infrastructure or surface the + facility is pointed at, and the authorization that permits it. See the + targeting rule below — this is the repo's most important control. +- **Rules of engagement.** What may be probed, where, with what credentials, + and what must never be done. An automated facility without this is + indistinguishable from the threat it models. +- **Findings delivery to the responsible party.** For our own estate that is + `risk-nexus`, which routes to the owning repo. For any other target it is + whoever is responsible for that infrastructure, on the terms agreed in the + engagement. + +## What it does not own + +- **Fixing anything.** A finding routes through `risk-nexus` to the repo that + owns the defect. A security facility that fixes things becomes a second + engineering team with no boundary and no reviewer. +- **Severity, disclosure and timing.** `risk-nexus`. This repo says what is + true; that repo says how much it matters and who hears about it. +- **Mechanical CI evidence.** Schema assertions, unit tests and provisioning + checks stay with the repo that owns the code. This repo does not take over + anyone's test suite. +- **Deciding what the security model should be.** NetKingdom's canon says what + good looks like. This repo says whether we have it. +- **Blocking delivery.** In build mode a finding is information. If that + changes it will be a recorded decision, not a habit that accretes. + +## The targeting rule + +The facility can be pointed at infrastructure we do not own. That is the point +of it, and it is also the single thing that could turn this repo from an asset +into a liability, so the rule is structural rather than cultural. + +**No target is probed without recorded authorization from whoever is +responsible for it. No exceptions.** + +- **Our own estate, build mode** — standing estate authorization is necessary + but not sufficient. Every live run still needs the dated engagement record, + target-owner acknowledgement and technique-specific scope required by the + rules of engagement. No live target is pre-authorized by this intent. +- **Our own estate, production** — a separate recorded authorization. Build-mode + standing consent does not carry across; the blast radius is different and so + is the decision. +- **Anything we do not own** — written authorization from the responsible party, + per engagement, recorded in this repo *before a packet is sent*. Scope, + window, permitted techniques, and named contacts on both sides. + +Three things that do **not** constitute authorization, written down because +each is a way teams talk themselves into it: a commercial relationship with the +target; the target being publicly reachable; and a belief that the owner "would +obviously be fine with it". Unauthorized probing may be unlawful regardless of +intent, and a white-hat facility that gets this wrong is simply an attacker +with better paperwork. + +**The authorization record is part of the finding.** A report that cannot name +the authorization it ran under is not a finding — it is an incident, and it +gets treated as one. + +**Scope creep during an engagement is prohibited.** A probe that discovers an +adjacent system stops at the boundary and reports what it saw. Following the +interesting thing is exactly how an authorized test becomes an unauthorized +one. + +## Honest limits on "automated" + +The word in the repo's description is *automated*, and it must not be oversold +— overclaiming is the failure this estate keeps catching in itself. + +External testing practice is consistent that the highest-impact cross-tenant +findings concentrate in access control, business logic and tenant isolation: +precisely the categories that need someone who understands what the data +*means* to recognise that a response is wrong. A response can be well-formed, +200, fast, and contain another tenant's rows. + +So: + +- **Automate the reproducible.** Structural conformance, differential responses + between tenant contexts, credential confinement, resource saturation. This is + most of the surface and it should run without anyone remembering to run it. +- **Flag the irreducible.** Where a finding requires semantic judgement, the + facility's job is to set up the conditions, capture the evidence, and mark it + for review with a date — not to return green. +- **A passing suite is not proof of isolation.** It is proof that the attacks + we thought of did not work. State it that way in every report, because the + gap between those two sentences is where breaches live. + +## The failure this repo must avoid + +**A probe that has only ever passed is not evidence.** `rapp-postgres` verified +its own drift check by deliberately breaking the thing it watched and +confirming the check failed. Every probe here inherits that obligation: it must +be shown to fail against a known-bad fixture before it is trusted against a +real system. + +The second failure is subtler. A probe that starts passing because it was +weakened is worse than a deleted probe, because it reports safety. Probe +changes are therefore reviewed as security changes, and a probe that begins +passing after a change to *itself* rather than to the system is treated as a +finding. + +## Relationship to the rest of the estate + +``` +whitehat-security → risk-nexus → policy-nexus + finds triages publishes + (severity, (permanent, + disclosure) addressable) +``` + +For our own estate it reads posture claims and canon from the repos that own +them, attacks the running systems those claims describe, and hands findings to +`risk-nexus`. For any other target, findings go to that infrastructure's +responsible party on the engagement's agreed terms; `risk-nexus` still records +that the engagement happened and what it means for us. + +It publishes nothing directly and fixes nothing, in either case. + +The first work is already specified and waiting: the E2 cross-tenant evidence +artifact, which is Tenancy Posture's highest-severity unowned gap, and the +noisy-neighbour characterisation, which the framework had to reword once +already because its first draft asserted something shared infrastructure cannot +provide. + +## What good looks like + +The estate knows which of its security claims have been tested, when, and by +what attacker model — and can tell the difference between a property that has +been verified and one that has merely never failed. diff --git a/README.md b/README.md index ac4e67a..b863063 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,26 @@ # whitehat-security -Automated white hat it-security, pen-testing and isolation-probing. \ No newline at end of file +NetKingdom's offensive security facility. Automated white hat IT-security, +pen-testing and isolation-probing — pointed at infrastructure we choose, +including our own. + +The estate's **adversarial evidence facility**: it attacks our own systems, on +a schedule, to find out whether the security properties they claim are actually +true. + +It exists because a repo testing its own boundary grades its own homework. The +probes most worth having are the ones an author would not think to write. + +- **Independent in operation.** It does not take a declared posture as true. + NetKingdom owns both the security canon and this facility, so findings leave + through `risk-nexus` under separate ownership rather than being resolved here. +- **It finds; it does not fix.** Findings route to `risk-nexus`, which owns + severity and disclosure. The repo that owns the defect owns the repair. +- **A pass means the attacks we tried did not work** — not that the boundary + holds. Reports say so. + +- Intent: [`INTENT.md`](INTENT.md) +- Scope: [`SCOPE.md`](SCOPE.md) +- Workplans: [`workplans/`](workplans/) +- Rules of engagement (pending operator approval): + [`docs/rules-of-engagement.md`](docs/rules-of-engagement.md) diff --git a/SCOPE.md b/SCOPE.md new file mode 100644 index 0000000..bc27a5a --- /dev/null +++ b/SCOPE.md @@ -0,0 +1,87 @@ +# Scope + +## One-liner + +`whitehat-security` is NetKingdom's authorization-bound offensive-security +tooling for producing adversarial evidence about security claims. + +## Core idea + +The repository turns stated security properties into dated, reproducible attack +attempts. It remains separate from the systems it tests, reports findings +without grading their severity, and never treats a passing probe as proof that a +boundary always holds. + +## In scope + +- Attacker models for tenant isolation, credential confinement, noisy-neighbour + behavior and erasure verification. +- Differential probes that compare behavior across controlled tenant contexts. +- Known-bad and known-good fixtures that demonstrate every probe can fail. +- Rules of engagement, target authorization, engagement records, abort + controls and evidence minimization. +- Probe cadence and the resulting assurance/exposure window. +- Delivery of findings and passing-run evidence to `risk-nexus`. + +## Out of scope + +- Fixing defects in target repositories. +- Assigning severity, disclosure policy or remediation deadlines. +- Replacing mechanical checks owned by a target repository's CI. +- Defining the estate's security model or publishing permanent policy. +- Probing any target without the authorization and engagement records required + by [the rules of engagement](docs/rules-of-engagement.md). +- Blocking build-mode delivery without a separately recorded decision. + +## Safety invariants + +- Until the rules of engagement receive personal operator approval, only + documentation and non-networked fixture design may proceed. +- No live target is authorized by this scope document. +- Every live run names its authorization, target, owner, window, technique, + credential lane, rate ceiling, abort contact and finding destination. +- A probe stops at the recorded boundary and never follows an adjacent system. +- Evidence records response shape and counts, never real tenant row values or + credentials. +- Findings leave this repository; repairs do not enter it. + +## Relevant when + +- A service claims a Tenancy Posture evidence level that requires adversarial + rather than mechanical evidence. +- A boundary must be tested using a leaked runtime credential or hostile tenant + context. +- The estate needs to know when a probe last ran, what attacker it modeled, and + whether it was proven against a known-bad fixture. + +## Not relevant when + +- A repository needs unit, schema or provisioning tests for its own code. +- A finding needs triage, severity or disclosure handling; use `risk-nexus`. +- Permanent policy needs publication; use `policy-nexus`. +- The desired activity falls outside an approved engagement boundary. + +## Current state + +- Repository status: active. +- Active plan: `WHITEHAT-WP-0001`. +- `T01` is in progress: the rules of engagement are drafted and awaiting + personal operator approval. +- No live probe traffic is authorized yet. +- `T02` through `T07` remain gated by `T01`. + +## Relationships + +- Owner and security canon: `net-kingdom`. +- Finding intake, severity and disclosure: `risk-nexus`. +- Permanent publication: `policy-nexus`. +- Initial proposed target owners: `tenant-engine`, `audit-core` and + `flex-auth`. + +## Getting oriented + +1. Read [`INTENT.md`](INTENT.md) for the durable purpose and ownership model. +2. Read [the rules of engagement](docs/rules-of-engagement.md) before any probe + design or execution. +3. Read [`WHITEHAT-WP-0001`](workplans/WHITEHAT-WP-0001-cross-tenant-evidence.md) + for active tasks and sequencing. diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md new file mode 100644 index 0000000..9efa35b --- /dev/null +++ b/WORK-RECORDS.md @@ -0,0 +1,18 @@ +# Work Records — whitehat-security + +> Generated by `statehub fix-consistency` (CUST-WP-0061-T04, work-record +> stage 3). Do not edit by hand — edit the source file/block listed for +> each record and re-run fix-consistency to refresh this index. Archived +> workplans are omitted; closed decisions/intakes/engagements stay listed +> so recently-resolved work is still visible. [auto] + +| Kind | ID | Status | Lane | Source | +| --- | --- | --- | --- | --- | +| workplan | WHITEHAT-WP-0001 | active | — | workplans/WHITEHAT-WP-0001-cross-tenant-evidence.md | +| task | WHITEHAT-WP-0001-T01 | progress | — | workplans/WHITEHAT-WP-0001-cross-tenant-evidence.md | +| task | WHITEHAT-WP-0001-T02 | wait | — | workplans/WHITEHAT-WP-0001-cross-tenant-evidence.md | +| task | WHITEHAT-WP-0001-T03 | wait | — | workplans/WHITEHAT-WP-0001-cross-tenant-evidence.md | +| task | WHITEHAT-WP-0001-T04 | wait | — | workplans/WHITEHAT-WP-0001-cross-tenant-evidence.md | +| task | WHITEHAT-WP-0001-T05 | wait | — | workplans/WHITEHAT-WP-0001-cross-tenant-evidence.md | +| task | WHITEHAT-WP-0001-T06 | wait | — | workplans/WHITEHAT-WP-0001-cross-tenant-evidence.md | +| task | WHITEHAT-WP-0001-T07 | wait | — | workplans/WHITEHAT-WP-0001-cross-tenant-evidence.md | diff --git a/docs/rules-of-engagement.md b/docs/rules-of-engagement.md new file mode 100644 index 0000000..3747aca --- /dev/null +++ b/docs/rules-of-engagement.md @@ -0,0 +1,145 @@ +# Rules of engagement for tenancy evidence + +Status: **pending personal operator approval** + +Version: 0.1 + +Date: 2026-08-18 + +Owner: NetKingdom / whitehat-security + +These rules authorize nothing outside their recorded scope. A probe without a +matching authorization record is prohibited, even if technically possible. + +## 1. Authorization classes + +| Target class | Required authorization | +| --- | --- | +| Offline known-good/known-bad fixtures created by this repo | This reviewed document | +| Estate build environment, non-destructive API differential probe | Standing estate authorization plus a dated engagement record naming the target owner | +| Any live Kubernetes workload, database credential, recovery or saturation probe | Separate operator approval for the named target, namespace, window and technique | +| Production | Production-specific written authorization; build-mode consent never carries over | +| Infrastructure not owned by the estate | Written authorization from its responsible party, per engagement, before any packet | + +Public reachability, a commercial relationship, and an assumption that an +owner would agree are never authorization. + +## 2. Engagement record + +Every run begins with a committed or operator-approved record containing: + +- engagement id, authorizer, approval timestamp and expiry +- target service, responsible repo/party, environment and namespace +- source location and network position of the probe +- exact API routes or database names in scope +- tenant fixtures and object identifiers created for the run +- credential lane, audience, role and maximum TTL (never the value) +- permitted techniques, prohibited techniques and concurrency/rate ceilings +- start/end window, operator contact and abort contact +- posture axis/claim and attacker model being tested +- finding destination in `risk-nexus` + +An expired, incomplete or mismatched record fails closed. Discovery of an +adjacent target is recorded and not followed. + +## 3. Initial authorized target envelope + +After personal approval of this document, offline fixtures may be built. No +live target is pre-authorized by this section. The first proposed live +engagements are: + +- `tenant-engine`: HTTP read/write differential using two disposable tenants +- `audit-core`: HTTP append/read differential using two disposable tenants +- `flex-auth`: decision differential for relationship inheritance across two + disposable tenants + +Each still needs its own dated engagement record and target-owner +acknowledgement. `databases/platform-pg` and `databases/apps-pg` are not in the +initial API-probe envelope; RLS, recovery and saturation work require separate +operator windows. + +## 4. Hard prohibitions + +- no destructive operation against data not created for the engagement +- no collection or exfiltration of real tenant row values; record only count, + schema shape, stable test-fixture ids and salted/one-run digests +- no denial-of-service, saturation, lock exhaustion, connection exhaustion or + large payload against shared substrate outside an explicitly approved window +- no superuser, `BYPASSRLS`, owner credential or standing privilege unless the + specific attacker model is testing detection of that misgrant +- no credential reuse outside its named audience/target and no credential + value in Git, evidence, State Hub, logs or chat +- no persistence, implant, account creation, lateral movement, vulnerability + chaining or follow-on discovery beyond the recorded technique +- no weakening alerting, backup, audit or retention controls to make a test pass + +## 5. Credentials and attribution + +Credentials are short-lived and obtained through the sanctioned custody lane. +The engagement records only the catalog/role reference, TTL and lease id if it +is safe metadata. The facility holds the same privilege as the modelled +workload—never broader privilege for convenience. + +HTTP probes send `User-Agent: whitehat-security/` and a stable +correlation id. Database probes set `application_name` to the engagement id. +The operator must be able to identify and terminate a probe from access logs or +`pg_stat_activity` without asking whether it is hostile traffic. + +## 6. Rate, concurrency and data controls + +API differential runs default to one in-flight request and at most 60 requests +per minute. A target owner may set a lower number. Test data uses two newly +created disposable tenants and deterministic synthetic values. Responses are +evaluated in memory; evidence stores status, count, content type, schema keys +and a salted run-local digest—not bodies. + +Database conformance defaults to one connection. Noisy-neighbour work has no +default: its connection/query/CPU ceiling must be written in the individual +operator-approved window. + +## 7. Abort and cleanup + +Any of these immediately aborts a run: + +- target latency/error rate crosses the engagement threshold +- a response appears to contain non-fixture tenant data +- scope, authorization, credential audience or target identity is uncertain +- operator/target owner requests stop +- audit attribution is absent +- an unexpected adjacent system responds + +The runner stops issuing work, closes HTTP/database sessions, revokes or lets +the bounded lease expire, and records the abort without attempting further +diagnosis. Cleanup deletes only fixtures whose ids are in the engagement +record. If cleanup cannot be proven, it becomes a finding; the runner does not +broaden privilege to force it. + +## 8. Evidence and reporting + +Every attempted run—pass, fail or abort—records: + +- authorization and engagement ids +- target revision/digest where observable without privilege escalation +- start/end timestamps and attacker model +- attempted operation count and response-shape comparison +- outcome: `pass`, `finding`, `inconclusive`, or `aborted` +- cleanup and credential-revocation outcome +- the statement: “Pass means only that the attacks attempted in this run did + not work; it is not proof that the tenant boundary always holds.” + +Findings route unchanged to `risk-nexus`; this repo assigns no severity and +does not fix the target. + +## 9. Change control + +Probe logic is security-sensitive. A change that makes a previously failing +known-bad fixture pass is a finding until independently explained. Every live +probe must first fail against its known-bad fixture and pass against the +known-good fixture in the same revision. + +## 10. Approval + +Personal operator approval is still required. Record approver, date and scope +in this section or an immutable linked decision before changing the status to +accepted. Until then, only documentation and non-networked test-fixture design +may proceed; no target packets are authorized by this draft. diff --git a/workplans/WHITEHAT-WP-0001-cross-tenant-evidence.md b/workplans/WHITEHAT-WP-0001-cross-tenant-evidence.md new file mode 100644 index 0000000..377ab7b --- /dev/null +++ b/workplans/WHITEHAT-WP-0001-cross-tenant-evidence.md @@ -0,0 +1,249 @@ +--- +id: WHITEHAT-WP-0001 +type: workplan +title: "Produce the adversarial evidence the Tenancy Posture ladders require" +domain: infotech +repo: whitehat-security +status: active +owner: net-kingdom +topic_slug: whitehat-security +created: "2026-08-17" +updated: "2026-08-21" +--- + +# WHITEHAT-WP-0001 — cross-tenant evidence + +## Goal + +Produce, on a schedule, the adversarial evidence artifacts that NetKingdom's +*Tenancy Posture* standard requires and no repo can honestly produce about +itself — starting with the one the framework calls its highest-severity gap. + +Done means: a service claiming `E2` has been attacked as an adversary holding +its runtime credential, the attempt is recorded with a date and an attacker +model, and a failure routes to `risk-nexus` rather than to a log nobody reads. + +## The forcing case + +*Tenancy Posture* open question 3 has been unowned since the framework was +drafted. What it calls a tenant-boundary failure the security industry calls +**Broken Object Level Authorization** — OWASP API1, top of the API Security Top +10 since that list launched, and the most commonly exploited API vulnerability +in published assessments. + +The estate has no coverage for it. `rapp-postgres` runs fifteen adversarial +probes and every one targets the *consumer* boundary — service versus service. +None targets the tenant boundary *inside* a consumer, which is where the +framework says the residual risk actually lives. + +## Rules of engagement — T01, and nothing else starts first + +An automated facility that probes systems without written scope is +indistinguishable from the threat it models. This is the gating task and it is +not paperwork. + +- **Target authorization**, the control that matters most now the facility is + scoped to any surface we choose rather than only our own. No target without a + recorded authorization from its responsible party. Our estate in build mode + has standing authorization only as a prerequisite: every live run still + needs the dated engagement record and target-owner acknowledgement defined in + the rules of engagement. Production needs its own authorization; anything we + do not own needs written per-engagement authorization recorded here before a + packet is sent. A commercial relationship, public reachability, and "they + would obviously be fine with it" are each explicitly not authorization. +- **Scope.** Which systems, which namespaces, which credentials — and a hard + stop at the engagement boundary. A probe that discovers an adjacent system + reports what it saw and does not follow it. +- **Prohibited actions**, stated as hard rules rather than intentions: + no destructive operations against data the estate did not create for the + test; no exfiltration of real tenant data even as proof of a finding — + a count and a schema shape are proof enough; no denial-of-service against a + shared substrate outside a declared window, because the connection ceiling + means a saturation probe is an outage for every co-resident. +- **Credentials.** The facility holds leased credentials like any workload, + through the sanctioned OpenBao lane. It gets no standing privilege, and + notably **no `BYPASSRLS` and no superuser** — an attacker would not have them + and a probe holding them proves nothing. +- **Attribution.** Every probe connection is identifiable as a probe in + `pg_stat_activity` and in logs, so an operator investigating an anomaly can + tell us from a real adversary in seconds. +- **Abort.** How a run is stopped, by whom, and what state it leaves behind. + +**Output:** `docs/rules-of-engagement.md`, reviewed by the operator personally. +This is exactly the class of thing `risk-nexus`'s escalation duty exists for. + +## Tasks + +### T01 — Rules of engagement +As above. Gates everything. + +```task +id: WHITEHAT-WP-0001-T01 +status: progress +priority: high +``` + +Drafted in `docs/rules-of-engagement.md` on 2026-08-18 with authorization +classes, per-run records, initial target envelope, hard prohibitions, +credential/attribution rules, rate defaults, abort/cleanup and evidence +schema. It authorizes no live traffic until the operator personally approves +§10. T01 remains progress and continues to gate every later task. + +### T02 — The attacker model per axis + +```task +id: WHITEHAT-WP-0001-T02 +status: wait +priority: high +``` + +What the adversary is assumed to hold, so a probe is judged against a threat +rather than against taste. Drawn from *Tenancy Posture* §4.3, which already +distinguishes them: + +| Axis | Adversary holds | Probe answers | +|---|---|---| +| E1/E2 | A legitimate runtime credential and the ability to make ordinary requests as tenant A | Can it reach tenant B's rows? | +| E3 | The above, plus SQL execution on the connection | Can it re-`SET` the tenant GUC and read across? | +| E4 | A leaked per-tenant credential | Can it address another tenant's substrate at all? | +| P1/P2 | A co-resident consumer behaving badly within its own allowance | What degradation do neighbours experience? | +| R | A copy of a backup taken before an erasure | Is the erased data still readable? | + +**Output:** `docs/attacker-model.md`. Note that the E3 row exists because the +framework corrected itself: E3 stops accident, not compromise, and a probe that +only tested accident would report a strength E3 does not have. + +### T03 — Differential cross-tenant harness (the E2 artifact) + +```task +id: WHITEHAT-WP-0001-T03 +status: wait +priority: high +``` + +The core technique: run the same request as two tenants and compare. + +- Provision two disposable tenants against a target service. +- Exercise its surface as tenant A; attempt every object identifier observed + from tenant B's context. +- Assert: B receives a denial or an empty result. **A well-formed 200 + containing A's data is the finding**, and the harness must be built to notice + that rather than to notice errors — both of this estate's real regressions + produced ordinary-looking responses, a 403 and a 404, and nothing alerted. +- Capture evidence as a count and a schema shape, never as tenant data (T01). + +**Acceptance:** run against `tenant-engine` and `audit-core`, both of which +currently claim `E2`. The artifact is the run record, not a green tick. + +### T04 — Prove the probes fail + +```task +id: WHITEHAT-WP-0001-T04 +status: wait +priority: high +``` + +A probe that has only ever passed is not evidence. + +Build known-bad fixtures — a service with a deliberately missing tenant +predicate — and confirm each probe fails against them. `rapp-postgres` verified +its drift check this way, by re-pinning to a bad digest and confirming exit 1; +the same discipline applies here and is not optional. + +**Acceptance:** every probe in T03 demonstrated failing before any of them is +trusted passing. + +### T05 — RLS conformance under attack (the E3 artifact) + +```task +id: WHITEHAT-WP-0001-T05 +status: wait +priority: medium +``` + +`rapp-postgres` ADR-0003 supplies an `rls_conformance` view and a template, and +states plainly that the platform's guarantee is **detection, not prevention** — +a table created by a later migration ships without a policy until something +notices. This repo is that something. + +- Query the conformance view on a cadence; any row is a finding. +- Attack what the view cannot see: a session that sets no GUC must read + nothing; a session with another tenant's value must see nothing; an insert + attributed to another tenant must be refused. +- Attempt the documented bypasses: a `SECURITY DEFINER` function owned by the + table owner, and a role holding `BYPASSRLS`. + +**Cadence is the deliverable here, not a detail.** For a detection-based +control the interval between runs *is* the exposure window, and ADR-0003 leaves +the number to this repo. Set it, and state the resulting window in the record. + +### T06 — Noisy-neighbour characterisation (the P1/P2 artifact) + +```task +id: WHITEHAT-WP-0001-T06 +status: wait +priority: medium +``` + +The framework had to reword this artifact once already: its first draft +required proof that a saturating consumer "does not breach" another's +allowance, which shared infrastructure cannot provide. + +What is achievable and therefore what this produces: a recorded baseline of +per-consumer resource usage; a run in which one consumer saturates its declared +allowance; evidence that the governance controls **bind**; and the degradation +co-residents experience, **measured and written down** rather than asserted +acceptable. + +Runs inside a declared window per T01 — on a single-node rail with a six- +consumer connection ceiling, a saturation probe is an outage if run carelessly. + +### T07 — Reporting into risk-nexus + +```task +id: WHITEHAT-WP-0001-T07 +status: wait +priority: medium +``` + +Findings leave this repo in one direction. A run produces: what was attempted, +under which attacker model, when, against which posture claim, and the outcome. +It carries no severity — that is `risk-nexus`'s. + +A **passing** run is also reported. "The attacks we thought of did not work" is +the honest claim, and recording it dated is what lets anyone see how stale the +assurance has become. + +## Sequencing + +T01 gates all. T02 shapes T03/T05/T06. T04 gates trusting any of them. T07 can +follow T03. + +## Risks + +**The facility becomes the threat.** Mitigated by T01, and by holding no +standing privilege. + +**Probes weaken silently.** A probe that starts passing after a change to +itself rather than to the system is a finding, not a fix. Probe changes are +reviewed as security changes. + +**Green is mistaken for safe.** Every report states that a pass means the +attacks attempted did not work, not that the boundary holds. + +**It drifts into fixing things.** The boundary in INTENT is load-bearing: +findings route out, work does not come in. + +## Open questions + +1. **Owner: NetKingdom** — settled 2026-08-17. Offensive security is security + work. The residual tension (NetKingdom owning both the Tenancy Posture + framework and the facility that tests conformance to it) is mitigated by + findings routing out to `risk-nexus` under separate ownership, and is + recorded in INTENT rather than argued away. +2. **Where probes run from.** In-cluster gives realistic network position; + outside gives independence from the substrate under test. Probably both, + eventually; pick one to start. +3. **Does a service get told it is being probed?** Announced runs are easier to + operate; unannounced ones test the alerting too. Build mode probably + announced, production probably not — which is itself a T01 decision.