Compare commits
3 commits
3fdad8d3c7
...
348738ba73
| Author | SHA1 | Date | |
|---|---|---|---|
| 348738ba73 | |||
| 0ce9f44ff9 | |||
| 77f574f50e |
9 changed files with 869 additions and 1 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.repo-manager/
|
||||
29
.repo-classification.yaml
Normal file
29
.repo-classification.yaml
Normal file
|
|
@ -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.
|
||||
123
AGENTS.md
Normal file
123
AGENTS.md
Normal file
|
|
@ -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 "<describe the need>" --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-<slug>.md`. Finished plans may
|
||||
move to
|
||||
`workplans/archived/YYMMDD-WHITEHAT-WP-NNNN-<slug>.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: "<uuid>" # 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: "<uuid>" # 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.
|
||||
|
||||
<!-- REPO-AGENTS-EXTENSIONS -->
|
||||
<!-- Add repository-specific instructions below this marker. -->
|
||||
193
INTENT.md
Normal file
193
INTENT.md
Normal file
|
|
@ -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.
|
||||
25
README.md
25
README.md
|
|
@ -1,3 +1,26 @@
|
|||
# whitehat-security
|
||||
|
||||
Automated white hat it-security, pen-testing and isolation-probing.
|
||||
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)
|
||||
|
|
|
|||
87
SCOPE.md
Normal file
87
SCOPE.md
Normal file
|
|
@ -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.
|
||||
18
WORK-RECORDS.md
Normal file
18
WORK-RECORDS.md
Normal file
|
|
@ -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 |
|
||||
145
docs/rules-of-engagement.md
Normal file
145
docs/rules-of-engagement.md
Normal file
|
|
@ -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/<engagement-id>` 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.
|
||||
249
workplans/WHITEHAT-WP-0001-cross-tenant-evidence.md
Normal file
249
workplans/WHITEHAT-WP-0001-cross-tenant-evidence.md
Normal file
|
|
@ -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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue