whitehat-security/probe-packs/tenant-engine-e2.json
tegwick beab2a04d1 Build authorization-gated tenancy evidence harness
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a0260c-4067-7052-9647-ad000d576e38
2026-08-21 23:53:27 +02:00

77 lines
3.4 KiB
JSON

{
"schema_version": "whitehat-probe-pack/v1",
"target": "tenant-engine",
"posture_claim": "E2",
"attacker_model": "docs/attacker-model.md#3-e2--authenticated-tenant-a-at-the-service-boundary",
"notes": [
"Actor identities must be real flex-auth-bound fixture identities; an allow-all authorizer is not target evidence.",
"TenantStore.events() is excluded because tenant-engine exposes no HTTP event-read route.",
"Writes require state-oracle reads before and after; response status alone is insufficient."
],
"probes": [
{
"id": "tenant-record-by-id",
"operation": "read",
"route": "GET /tenants/{tenant_b_id}",
"owner": "tenant B actor reads tenant B fixture",
"attacker": "tenant A actor substitutes tenant B id",
"absent": "tenant A actor reads a reserved absent tenant id",
"finding": "tenant B marker is returned or existence differs from absent"
},
{
"id": "tenant-roles-cache",
"operation": "read",
"route": "GET /tenants/{tenant_b_id}/roles",
"owner": "tenant B cache-reader reads tenant B roles",
"attacker": "tenant A cache-reader substitutes tenant B id",
"absent": "tenant A cache-reader reads a reserved absent tenant id",
"finding": "tenant B role state is returned or existence differs from absent"
},
{
"id": "tenant-roles-live",
"operation": "read",
"route": "GET /tenants/{tenant_b_id}/roles/live",
"owner": "tenant B live-reader reads tenant B roles",
"attacker": "tenant A live-reader substitutes tenant B id",
"absent": "tenant A live-reader reads a reserved absent tenant id",
"finding": "tenant B role state is returned or existence differs from absent"
},
{
"id": "tenant-guardrails",
"operation": "read",
"route": "GET /tenants/{tenant_b_id}/guardrails",
"owner": "tenant B actor reads tenant B guardrails",
"attacker": "tenant A actor substitutes tenant B id",
"absent": "tenant A actor reads a reserved absent tenant id",
"finding": "tenant B limit state is returned or existence differs from absent"
},
{
"id": "tenant-role-grant",
"operation": "create",
"route": "POST /tenants/{tenant_b_id}/roles/grant",
"owner": "tenant B operator creates a disposable control grant",
"attacker": "tenant A operator substitutes tenant B id",
"absent": "tenant A operator targets a reserved absent tenant id",
"finding": "grant succeeds or tenant B role state changes"
},
{
"id": "tenant-plan-assign",
"operation": "update",
"route": "POST /tenants/{tenant_b_id}/plan",
"owner": "tenant B operator assigns a disposable control plan",
"attacker": "tenant A operator substitutes tenant B id",
"absent": "tenant A operator targets a reserved absent tenant id",
"finding": "assignment succeeds or tenant B plan state changes"
},
{
"id": "tenant-lifecycle-and-guardrail-writes",
"operation": "update",
"route": "PATCH/POST/PUT/DELETE /tenants/{tenant_b_id}/...",
"owner": "tenant B operator exercises each authorized fixture mutation",
"attacker": "tenant A operator substitutes tenant B id in update, retire, reactivate, grouping and guardrail routes",
"absent": "tenant A operator targets a reserved absent tenant id",
"finding": "any mutation succeeds or tenant B ETag/state changes"
}
]
}