Skip to content

OpenFreyt Protocol — Abuse Case Catalogue

Generated from security/abuse-cases.md. Edit the canonical source file, not this page.

Status: Normative
Version: 1.0.0-draft
Locked by: M001-S01-T03
Last reviewed: 2026-08-31


This catalogue documents adversarial abuse cases for the OpenFreyt Protocol (PCX). Each entry describes a concrete attack scenario from an attacker’s perspective, the protocol controls that prevent or limit it, and the residual risk.

Abuse cases complement the threat model. Where the threat model organises findings by threat category, this catalogue organises them by attacker goal and concrete exploitation technique.

Required coverage per task plan:

  1. Unauthorized data access via UUID guessing
  2. Double-commitment race
  3. Stale decision replay
  4. Scope elevation
  5. Relationship flood
  6. Webhook SSRF
  7. Oversized payload DoS
  8. Decision policy bypass
  9. Audit trail poisoning
  10. Token audience confusion

AC-01 — Unauthorized Data Access via UUID Guessing

Section titled “AC-01 — Unauthorized Data Access via UUID Guessing”

Goal: Access CapacityOffer or LoadRequest records belonging to another organization.

Preconditions:

  • Attacker holds a valid JWT with capacity:read or loads:read scope for their own organization.
  • Attacker knows the general UUID format used by the broker.

Attack steps:

  1. Observe one or more resource IDs from legitimate API responses (e.g., own CapacityOffer IDs).
  2. Attempt to infer ID generation patterns (sequential counters, timestamp-based prefixes).
  3. Enumerate IDs by issuing GET requests with mutated or incremented UUIDs.
  4. For UUIDv7 IDs, attempt timestamp-range scanning: generate all UUIDv7 values for a known creation time window and iterate.
  5. If any guessed ID returns data, read confidential counterparty payload.

Protocol controls:

  • All resource IDs are UUIDv7 with a randomly generated 62-bit node/clock-seq component; the probability of a valid guess for a single request is ≈ 2⁻⁶² ≈ 2.2 × 10⁻¹⁹.
  • Every resource GET filters on ownerOrganizationId derived from the token’s org_id claim; a correct UUID belonging to another org returns 404 Not Found (never 403), per R-001.
  • Brokers MUST apply rate limiting on read endpoints (per-org, per-token); aggressive enumeration triggers 429 Too Many Requests before a statistically meaningful number of IDs can be tested.

Residual risk: NEGLIGIBLE — the combination of 62-bit entropy and 404-not-403 renders systematic guessing computationally infeasible and observationally indistinguishable from legitimate not-found responses.

Related threats: T-06 (Resource Enumeration Resistance), API1.


Goal: Commit the same MatchDecision twice, creating duplicate binding records or bypassing bilateral approval requirements.

Preconditions:

  • Attacker controls one side of a bilateral MatchDecision (e.g., the initiator organization).
  • Attacker can issue concurrent HTTP requests.

Attack steps:

  1. Obtain a MatchDecision in PENDING_INITIATOR_ACCEPT state.
  2. Issue two or more simultaneous COMMIT (or ACCEPT) requests with the same payload.
  3. If the broker uses non-serialized writes, both requests may pass a read-check-write sequence concurrently before either commits, causing two state transitions.
  4. Alternatively, issue one ACCEPT and immediately one COMMIT before the ACCEPT is persisted, attempting to skip the bilateral approval gate.

Protocol controls:

  • Every mutating state transition on a MatchDecision MUST use a compare-and-swap on resourceVersion; only one transition can win the CAS; all others receive 409 Conflict.
  • The resourceVersion field is a monotonically increasing integer; the client MUST supply the current version in the request body; mismatches are rejected.
  • Idempotency keys are REQUIRED on all mutating requests; a duplicate idempotency key within the idempotency window (24 h) returns the original result without re-executing.
  • State machine is defined such that a COMMIT from state PENDING_ACCEPTOR_ACCEPT is rejected; the machine enforces ordering regardless of concurrency.

Residual risk: LOW — CAS + idempotency keys eliminate the double-commit window.

Related threats: T-12 (Double-Commitment Race), API5.


Goal: Re-apply an old ACCEPT or COMMIT action on a MatchDecision that has since moved to a terminal state (REJECTED, EXPIRED, or COMMITTED), resurrecting a dead commitment.

Preconditions:

  • Attacker captured a valid signed ACCEPT request from a prior session.
  • The MatchDecision has since been REJECTED by the counterparty or has EXPIRED.

Attack steps:

  1. Re-send the captured ACCEPT request verbatim, using the original idempotency key, or with a new idempotency key to bypass the idempotency cache.
  2. If the broker does not validate terminal state transitions, the decision is incorrectly re-activated.
  3. Attacker now holds a fraudulently re-activated commitment.

Protocol controls:

  • State machine explicitly defines terminal states (REJECTED, EXPIRED, COMMITTED, CANCELLED). Transitions into or from terminal states are PROHIBITED; any attempt returns 409 Conflict with currentState in the error body.
  • The resourceVersion in the replayed request will not match the current version of the terminal record; CAS rejects the transition.
  • Idempotency key cache stores the terminal outcome; a replay within the cache window returns the original rejected/expired response.
  • Webhook delivery timestamps are validated against a 300 s window; replayed webhook events are discarded.

Residual risk: LOW — terminal state + versioned CAS prevents resurrection.

Related threats: T-04 (Replay Resistance), API5.


Goal: Perform an operation (e.g., COMMIT a MatchDecision, write an OutcomeReport) using a token that was granted only a lower-privilege scope (e.g., matches:read).

Preconditions:

  • Attacker holds a valid JWT with a read-only scope.
  • Attacker understands the API surface sufficiently to craft valid request payloads.

Attack steps:

  1. Obtain a matches:read token (e.g., through a compromised read-only service account).
  2. Issue a POST to /match-decisions/{id}/accept with a valid body, expecting the broker to validate only authentication and not scope.
  3. If scope validation is missing or misimplemented (e.g., only checking for any valid token), the ACCEPT succeeds with a read scope.

Protocol controls:

  • Each endpoint declares a minimum required scope in the authorization matrix; the middleware MUST reject requests where the token’s scope claim does not include the required scope before any handler logic runs.
  • Scope check is performed BEFORE ownership check to avoid information leakage about valid IDs.
  • Scope strings are exact-match only; matches:read does NOT imply matches:decide.
  • The 9 PCX scopes form a non-hierarchical flat set; there is no implicit scope inheritance.

Residual risk: LOW — flat non-hierarchical scope set eliminates implicit elevation.

Related threats: T-03 (Token Audience and Scope Validation), API5.


Goal: Exhaust broker storage and processing capacity by creating a large number of PartnerRelationship invite records, consuming quota or triggering notification storms.

Preconditions:

  • Attacker holds a valid JWT with relationships:manage scope.
  • Attacker can generate many distinct target organizationId values (real or fabricated).

Attack steps:

  1. In a tight loop, issue POST /partner-relationships with a different target organization ID per request.
  2. Each invite creates a pending PartnerRelationship record and triggers a notification to the target organization.
  3. At scale, this floods the target organization’s notification inbox and consumes broker storage quota.
  4. Alternatively, flood the same target with repeated invites after each is declined.

Protocol controls:

  • Per-organization rate limit on relationships:manage write operations (normative minimum: 10 invites per minute, 50 per hour, configurable by broker).
  • Broker MAY enforce a maximum number of PENDING outbound relationships per organization (recommended cap: 100).
  • Duplicate invite detection: a second invite to the same target organization while one is already PENDING MUST return 409 Conflict rather than creating a second record.
  • Invite payload is size-limited (64 KiB maximum body); no large embedded documents.

Residual risk: LOW — rate limits and duplicate detection prevent flood at protocol level; brokers tune thresholds per deployment.

Related threats: T-08, API4 (Unrestricted Resource Consumption).


Goal: Use the broker’s webhook delivery infrastructure as a proxy to reach internal services (metadata APIs, internal databases, internal admin endpoints) that are inaccessible from the attacker’s network.

Preconditions:

  • Attacker holds a valid JWT with relationships:manage scope (webhook URL is set during PartnerRelationship creation or update).
  • Attacker knows or can guess an internal URL (e.g., http://169.254.169.254/latest/meta-data/ for AWS IMDSv1, or http://10.0.0.1/admin).

Attack steps:

  1. Register a PartnerRelationship with webhookUrl set to an internal endpoint URL.
  2. Trigger a protocol event (e.g., capacity published) that causes the broker to deliver a webhook POST to the configured URL.
  3. If the broker does not validate the URL, the POST reaches the internal endpoint.
  4. Observe the webhook delivery response payload (echoed back in delivery logs or API response) to exfiltrate internal service responses.

Protocol controls:

  • Webhook URL validation at registration time MUST:
    • Reject http:// scheme (HTTPS only).
    • Resolve the hostname and reject if it resolves to: RFC 1918 ranges (10/8, 172.16/12, 192.168/16), loopback (127/8, ::1), link-local (169.254/16, fe80::/10), or cloud metadata addresses (169.254.169.254, fd00:ec2::254).
    • Reject URLs with embedded credentials (https://user:pass@host/).
  • DNS re-resolution at delivery time with the same blocklist (prevents DNS rebinding).
  • HTTP redirect following is PROHIBITED; 3xx responses cause delivery failure.
  • Delivery response body is NOT echoed back to the registering organization in API responses or logs (prevents exfiltration).
  • Delivery is performed by a dedicated egress process with no access to internal credential stores or metadata endpoints.

Residual risk: MEDIUM — DNS rebinding with short TTLs remains a theoretical vector; bounded by time-limited re-validation on each delivery attempt (TTL floor: 60 s) and isolated egress network segment recommendation.

Related threats: T-05 (Webhook Authentication), API7 (SSRF).


Goal: Exhaust broker memory, CPU, or storage by submitting extremely large JSON payloads, causing out-of-memory errors, parser slowdowns, or disk exhaustion.

Preconditions:

  • Attacker holds any valid JWT with a write scope.

Attack steps:

  1. Construct a JSON body significantly larger than a legitimate resource payload (e.g., 50 MB CapacityOffer with a large notes string or deeply nested externalReferences array).
  2. POST to any write endpoint (e.g., POST /capacity-offers).
  3. If the broker reads the full body before validating size, the parser allocates memory for the entire payload, causing memory pressure or OOM.
  4. Repeat concurrently from multiple tokens to amplify impact.

Protocol controls:

  • API boundary enforces maximum request body size before parsing:
    • Standard resources: 256 KiB.
    • PartnerRelationship payloads: 64 KiB.
    • Requests exceeding limits receive 413 Payload Too Large immediately without body parsing.
  • externalReferences array is limited to a maximum of 20 items; each item is a string of maximum 512 characters.
  • Per-organization write rate limits prevent sustained flood from a single token.
  • Schema validation rejects unexpected deeply-nested structures before any business logic runs.

Residual risk: LOW — body-size enforcement at the boundary prevents parser exploitation.

Related threats: T-08 (Oversized Payload Handling), API4.


Goal: Commit a MatchDecision without obtaining the counterparty’s consent, by exploiting a misconfigured or improperly enforced decision policy.

Preconditions:

  • Attacker controls one organization in a bilateral PartnerRelationship.
  • The PartnerRelationship uses BILATERAL_REQUIRED decision policy (the default).

Attack steps:

  1. Create a MatchDecision as the initiator.
  2. Issue two ACCEPT requests from two different member accounts of the same organization (not the counterparty), attempting to satisfy the “two-party acceptance” check using own members.
  3. Alternatively, manipulate the PartnerRelationship decisionPolicy field after the relationship is established, changing it from BILATERAL_REQUIRED to INITIATOR_ONLY, then issue a single ACCEPT to commit.
  4. Alternatively, find an endpoint that applies the wrong policy for a given decision or skips policy validation on the COMMIT path.

Protocol controls:

  • Decision policy is immutable after PartnerRelationship activation; updates to decisionPolicy are REJECTED with 422 Unprocessable Entity once the relationship is in ACTIVE state.
  • BILATERAL_REQUIRED state machine evaluates acceptance against the two distinct organization IDs stored at MatchDecision creation time, not against the calling token’s org_id.
  • A second ACCEPT from the same organizationId as the first ACCEPT is idempotent and does not advance the state to COMMITTED; state only advances when a distinct second organizationId submits ACCEPT.
  • COMMIT is not a distinct endpoint; it is the implicit result of the second distinct ACCEPT under BILATERAL_REQUIRED. Brokers MUST NOT expose a separate COMMIT endpoint that bypasses policy evaluation.

Residual risk: LOW — policy immutability and org-ID-based evaluation eliminate the bypass paths above.

Related threats: T-12, API5 (Broken Function Level Authorization), API6.


Goal: Insert false, modified, or deleted entries into the audit log to conceal unauthorized actions or frame a legitimate organization.

Preconditions:

  • Attacker has write access to the audit log via application-layer API (no direct DB access).
  • Alternatively, attacker has compromised an application service account.

Attack steps:

  1. Issue API calls that normally generate audit events, then attempt to DELETE or PATCH the corresponding audit log entries via the API.
  2. Submit a crafted OutcomeReport with a forged timestamp to backdate an event.
  3. Issue audit events using a legitimate token to falsely attribute actions to a different organization member.
  4. Flood the audit log to push older genuine entries out of the retention window.

Protocol controls:

  • Audit log entries are append-only; there is no DELETE or PATCH endpoint for audit records.
  • Audit entries are written by the protocol service itself, not accepted from clients; clients cannot inject audit entries directly.
  • Each audit entry includes the server-generated createdAt timestamp and the token’s sub claim; client-supplied timestamps are ignored.
  • Audit entries include a cryptographic chaining hash (SHA-256 of previous entry + current payload) to detect gaps or insertions.
  • outcomes:review scope provides read-only access to audit records; no write scope exists for the audit log API.
  • Retention window is enforced by the broker; volume-based flooding is bounded by write rate limits and storage quotas.

Residual risk: LOW — append-only + chained hashes make tampering detectable.

Related threats: T-09 (Sensitive Log Redaction), API6.


Goal: Use a JWT issued for one PCX service (e.g., a reporting service) to authenticate against a different PCX service (e.g., the core broker API), gaining unintended access.

Preconditions:

  • Attacker holds a valid JWT with a broad or wrong aud claim.
  • Multiple PCX services share the same signing key or the broker does not validate aud.

Attack steps:

  1. Obtain a JWT issued for aud: pcx-reporting.example.com with broad scopes.
  2. Present this token to the core broker API at pcx-broker.example.com.
  3. If the broker validates signature only (not aud), the token is accepted and the attacker gains access to broker resources.
  4. Alternatively, obtain a JWT issued for an internal service-to-service call (e.g., a batch job with capacity:publish scope) and use it to publish capacity offers on behalf of an organization the batch job should not control.

Protocol controls:

  • The broker MUST validate that the aud claim contains its own service identifier (a non-guessable URL or URN configured at deployment time).
  • Tokens with aud that does not exactly match (or contain) the broker’s expected audience are rejected with 401 Unauthorized before scope or org checks run.
  • Service-to-service internal tokens MUST use a separate aud value that is not accepted by the external broker API.
  • JWKS endpoint is pinned at configuration time; dynamically discovered JWKS endpoints are PROHIBITED without explicit allow-listing.
  • The org_id claim in the token ties every authorized action to a specific organization; even a valid broad-scope token cannot act for an organization it was not issued for.

Residual risk: LOW — strict aud validation at the gateway eliminates cross-service reuse.

Related threats: T-03 (Token Audience and Scope Validation), API2 (Broken Authentication).


AC ID Abuse Case Residual Risk Status
AC-01 UUID guessing NEGLIGIBLE ACCEPTED
AC-02 Double-commitment race LOW ACCEPTED
AC-03 Stale decision replay LOW ACCEPTED
AC-04 Scope elevation LOW ACCEPTED
AC-05 Relationship flood LOW ACCEPTED
AC-06 Webhook SSRF MEDIUM ACCEPTED — DNS rebinding residual; time-bounded re-validation required
AC-07 Oversized payload DoS LOW ACCEPTED
AC-08 Decision policy bypass LOW ACCEPTED
AC-09 Audit trail poisoning LOW ACCEPTED
AC-10 Token audience confusion LOW ACCEPTED

No unresolved CRITICAL or HIGH findings.
The single MEDIUM residual risk (AC-06 DNS rebinding) is accepted with the requirement for a 60-second TTL floor and an isolated egress network segment. This risk is reviewed at M002 (webhook delivery implementation milestone).