Owner acknowledgement remains pending. Offline admission stays fail-closed. No credentials requested and no packets sent. Assistant: grok Assistant-Session: 01a02670-3345-76f2-a014-70fde8e2a2bb
353 lines
16 KiB
Markdown
353 lines
16 KiB
Markdown
---
|
|
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-22"
|
|
state_hub_workstream_id: "ecc16edc-9f9b-4fc4-8fb1-96b947a59299"
|
|
---
|
|
|
|
# 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: done
|
|
priority: high
|
|
state_hub_task_id: "0d28fd14-1b82-4ac1-907b-02f43e8baae8"
|
|
```
|
|
|
|
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. The operator accepted v0.1 on 2026-08-21 with the scope recorded in
|
|
what is now §11. v0.2 (2026-08-22) adds §10, the governed test plane, as a
|
|
stricter admission control. It does not expand authorization. The acceptance
|
|
approves the operating rules and offline fixture work; it does not
|
|
pre-authorize any live target.
|
|
|
|
### T02 — The attacker model per axis
|
|
|
|
```task
|
|
id: WHITEHAT-WP-0001-T02
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "e0070ee6-6060-4a29-bd88-f664034db28e"
|
|
```
|
|
|
|
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`, completed 2026-08-21. It separates
|
|
credential-bearing tenant attacks, omitted-predicate accidents, SQL-capable
|
|
compromise, structural credential confinement, bounded co-resident saturation,
|
|
and both R4 erasure routes. It preserves the framework's correction that E3
|
|
stops accident, not compromise: resetting the tenant GUC after SQL execution
|
|
is recorded as E3's documented limit, not misreported as an E3 conformance
|
|
failure.
|
|
|
|
### T03 — Differential cross-tenant harness (the E2 artifact)
|
|
|
|
```task
|
|
id: WHITEHAT-WP-0001-T03
|
|
status: progress
|
|
priority: high
|
|
state_hub_task_id: "742561f1-97b6-4fcc-8e06-d18508ddecae"
|
|
```
|
|
|
|
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:** a dated run record against every *applicable* E2 target. The
|
|
artifact is the run record, not a green tick. `tenant-engine` is registered
|
|
`not_applicable` for E2; that record is the artifact for that target.
|
|
`audit-core` remains the live E2 target and still needs a new admitted
|
|
engagement.
|
|
|
|
Implementation progress, 2026-08-22: `src/whitehat_security/differential.py`
|
|
performs owner/attacker/absent comparisons, detects fixture disclosure and
|
|
write-side state change, and persists only sanitized observations. Live entry
|
|
is `execute_authorized`, which requires a plane lease. Concrete route
|
|
inventories live in `probe-packs/`. Target honesty lives in `targets/`:
|
|
`audit-core` is applicable; `tenant-engine` is `not_applicable` (that is the
|
|
artifact, not a deferral); `flex-auth` is pending.
|
|
|
|
The 2026-08-21 production engagement IDs were cancelled without sending a
|
|
target request and are retired. ops-mason applied the foundational plane on
|
|
2026-08-22. The operator approved `WH-ENG-20260822-AUDIT-E2-01` at
|
|
2026-08-22T09:52:55Z. Target-owner acknowledgement and the custody broker
|
|
remain pending. Offline preflight must fail closed until both exist. Whitehat
|
|
will not relabel tenant-engine to finish this task.
|
|
|
|
### T04 — Prove the probes fail
|
|
|
|
```task
|
|
id: WHITEHAT-WP-0001-T04
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "a2afc0f5-3ece-410c-864c-829a8aac30fc"
|
|
```
|
|
|
|
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.
|
|
|
|
Completed 2026-08-22. Five generic read/list/create/update/delete probes and
|
|
the three audit-core shaped probes pass the enforcing in-process fixture and
|
|
all produce findings when the tenant predicate is removed. Tenant-engine has
|
|
no applicable E2 identity, so its pack is not calibrated as if it were E2.
|
|
`make fixture-evidence` refreshes `evidence/offline-calibration.json`.
|
|
Target probes are still not trusted passing against a live service until a
|
|
new admitted engagement runs.
|
|
|
|
### T05 — RLS conformance under attack (the E3 artifact)
|
|
|
|
```task
|
|
id: WHITEHAT-WP-0001-T05
|
|
status: progress
|
|
priority: medium
|
|
state_hub_task_id: "6df676e7-bed5-4291-a128-eb6e9844edf2"
|
|
```
|
|
|
|
`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.
|
|
|
|
Implementation progress, 2026-08-22: the cadence is fixed at 24 hours plus run
|
|
and reporting latency, with event-triggered pre-promotion runs after schema,
|
|
role, RLS or security-definer changes. `src/whitehat_security/e3.py` encodes the
|
|
seven expected outcomes, keeps the SQL-compromise GUC reset labeled as E3's
|
|
documented limit, and calibrates known-good/known-bad in-process. `platform-pg`
|
|
is registered `pending`. A live database run still requires its separate
|
|
authorized target, named database, ordinary runtime role, and window.
|
|
|
|
### T06 — Noisy-neighbour characterisation (the P1/P2 artifact)
|
|
|
|
```task
|
|
id: WHITEHAT-WP-0001-T06
|
|
status: progress
|
|
priority: medium
|
|
state_hub_task_id: "99254ab5-f08e-44c7-8399-be706dc03019"
|
|
```
|
|
|
|
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.
|
|
|
|
Implementation progress, 2026-08-22: `src/whitehat_security/capacity.py`
|
|
records baseline/loaded latency, errors and throughput per consumer, governor
|
|
binding, aggressor peak/ceiling and neighbour degradation. The in-process
|
|
fixture is registered as `fixture-capacity`. `shared-substrate` is `pending`.
|
|
No live load has been generated; the required operator-approved substrate
|
|
window and aggressor ceiling do not yet exist.
|
|
|
|
### T07 — Reporting into risk-nexus
|
|
|
|
```task
|
|
id: WHITEHAT-WP-0001-T07
|
|
status: progress
|
|
priority: medium
|
|
state_hub_task_id: "54f33288-5361-4b20-8e1f-168866d64644"
|
|
```
|
|
|
|
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.
|
|
|
|
Implementation progress, 2026-08-22: `schemas/run-report.schema.json` defines
|
|
the minimized evidence contract, `whitehat risk-message` renders both pass
|
|
and finding deliveries without severity, and `whitehat deliver` queues a
|
|
target report to `outbox/`. Fixture calibration is refused as target
|
|
assurance. Completion awaits the first authorized target report being
|
|
delivered to `risk-nexus`.
|
|
|
|
### T08 — Governed test plane
|
|
|
|
The 2026-08-22 cutoff's missing infrastructure, encoded here so live work can
|
|
resume later without assembling authority during the run.
|
|
|
|
```task
|
|
id: WHITEHAT-WP-0001-T08
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "965ab027-efde-48b7-bb13-84dd308b909d"
|
|
```
|
|
|
|
Completed 2026-08-22 as a repository contract, not a cluster provision:
|
|
|
|
- Target registration schema and catalog, including an honest
|
|
`not_applicable` state.
|
|
- Fail-closed admission: retired IDs, kill switch, approval class, namespace,
|
|
pinned digest, known-bad calibration, two identity handles.
|
|
- Credential broker interface that never returns secret values. The live
|
|
broker is unconnected and raises before any custody call.
|
|
- Rate watcher, lease cleanup, default-deny plane manifests, runner identity.
|
|
- Automatic outbox delivery of target reports only.
|
|
|
|
`ops-mason` was asked on 2026-08-22 to provision only the namespace, default
|
|
deny policy and runner service account from `plane/`. That message does not
|
|
authorize a pod, a credential, or traffic. A real custody projection still
|
|
waits on a new engagement ID.
|
|
|
|
## Sequencing
|
|
|
|
T01 gates all. T02 shapes T03/T05/T06. T04 gates trusting any of them. T08
|
|
gates live T03. T07 can follow T03.
|
|
|
|
## Session cutoff — 2026-08-22
|
|
|
|
The coordinating session ended with the workplan deliberately **active**. T01,
|
|
T02, T04 and T08 are done. T03, T05, T06 and T07 remain in progress. The two
|
|
dated production engagement records were cancelled without sending any target
|
|
request; cancelled engagement IDs are terminal and must never be reused.
|
|
|
|
The offline instrument is implemented, calibrated, and plane-gated. The
|
|
estate still has to provision the cluster plane and a value-safe credential
|
|
broker before any live evidence exists. Resume only with new engagement IDs.
|
|
The exact completed scope is recorded in `docs/session-cutoff-2026-08-22.md`
|
|
and `docs/test-plane.md`.
|
|
|
|
## 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.
|