Relayboard external web/API security review
A clean-room example of how Defence records a property break, the evidence behind it, remediation, and what a targeted retest does—and does not—close.
- Report ID
- DEF-SYN-001
- Version
- 1.0
- State
- Final illustrative report
- Assessment window
- 18–19 Aug 2026
- Retest window
- 22 Aug 2026
- Environment
- Production-like synthetic environment
- Current build
- relayboard-web 2026.08.22.3
- Generated
- 25 Aug 2026 · 11:40 UTC
- Accountable author
- Defence review team
Executive verdict
This report does not establish that Relayboard has no other vulnerabilities or that the changed build received a new full assessment.
Two authorization boundaries and one single-use workflow condition were confirmed with synthetic test data.
Only SYN-01 has closure evidence. SYN-02 retains a sibling-path break. SYN-03 has a reported fix but no replay evidence.
Unresolved work
- Close the observer path on bulk job operations, then repeat the full route-family matrix.
- Replay magic-link consumption against build 2026.08.22.3 before calling SYN-03 closed.
- Provide a rate-limit test window to resolve the remaining session-throttling blocker.
Priority actions
- 01Finish the job route family
The single-item fix does not protect bulk-close. Apply one server-side policy across both operations and retest denied and allowed roles.
Owner: API team - 02Retest the atomic consume change
A reported fix is not closure evidence. Repeat sequential and concurrent consumption with a same-link control.
Owner: Identity team - 03Resolve the throttling blocker
Approve a bounded request-rate window so the remaining applicable session direction can receive an honest disposition.
Owner: Product + Defence
System and scope
The frozen surface contains one fictional multi-tenant field-work product and only test-team identities, workspaces, jobs, exports, and magic links.
- Web application
- app.relayboard.example
- HTTP API
- api.relayboard.example
- Assessment build
- relayboard-web 2026.08.18.5
- Retest build
- relayboard-web 2026.08.22.3
In scope
- Authenticated role and tenant boundaries on the named web/API surface.
- Owned test identities and synthetic objects only.
- Bounded read and reversible workflow-state effects.
Out of scope
- Source code, cloud configuration, internal networks, availability testing, and third-party assets.
- Real customer records, real payments, persistence, messaging, and destructive actions.
- Effect ceiling
- Synthetic object read and reversible state transition. No real-user or financial effect permitted.
- Stop conditions
- Unexpected customer data, live credentials, real-money paths, service instability, or an unapproved host stop the test and trigger redaction/escalation.
- Methodology registry
- Defence external review model 1.0 · OWASP WSTG 4.2 · OWASP API Security Top 10 2023 · HackTricks snapshot 2026-08-18
Findings register
Three reproduced conditions, ordered by decision urgency. Current state is independent from severity.
| ID | Finding | Expected property | Severity | Current state |
|---|---|---|---|---|
| SYN-01 | Cross-workspace export download | Session workspace, route workspace, and export owner must match before a download is issued. | High | Closed under retest |
| SYN-02 | Observer closes jobs through a sibling operation | Only dispatcher or owner may move a job into closed state across every operation in the route family. | Medium | Partially remediated |
| SYN-03 | Magic link can be consumed twice | One synthetic magic link creates at most one authenticated session, including concurrent consumption. | Medium | Fixed — not retested |
Cross-workspace export download
Closed for the named condition on build 2026.08.22.3. Reopen after material changes to export authorization or storage routing.
GET /v2/workspaces/{workspace_id}/exports/{export_id}/download- Synthetic export exp_042 belongs to ws_cobalt.
- The test actor has no membership in ws_cobalt.
Three ownership signals must agree.
The session, route, and export record define one workspace boundary. A file is returned only when all three resolve to the same owned workspace.
EvidenceEV-101
The route workspace did not constrain the export lookup.
Changing only the synthetic export identifier returned a file owned by ws_cobalt to the ws_amber observer.
EvidenceEV-101 · EV-102
The lookup and policy were bound to the workspace.
The remediation requires a composite lookup and authorization before response streaming—not a hidden link or changed client message.
EvidenceEV-103
Denied and allowed controls now separate correctly.
The foreign export returned 404 with no body; the same-workspace owner control still returned the synthetic file.
EvidenceEV-103
Evidence
EV-101 · EV-102 · EV-103
Synthetic request excerptSynthetic evidence
GET /v2/workspaces/ws_cobalt/exports/exp_042/download Cookie: session=<REDACTED TEST SESSION> X-Test-Workspace: ws_amber
Bounded excerpt · no public verification hash
Synthetic response excerptSynthetic evidence
HTTP/2 200 content-type: text/csv content-length: 183 body: <SYNTHETIC EXPORT EXCERPT>
Bounded excerpt · no public verification hash
Control observationSynthetic evidence
ws_amber owner + exp_amber_017 → 200 ws_amber observer + exp_042 → 200 before fix same session; only workspace/export pair changed
Bounded excerpt · no public verification hash
Consequence boundary
- Expected
- The foreign export is not returned and no object-existence detail crosses the workspace boundary.
- Observed
- The ws_amber observer received the invented ws_cobalt CSV export with HTTP 200.
- Demonstrated
- A user from one synthetic workspace read a file owned by another synthetic workspace.
- Possible, not demonstrated
- The same condition could expose other exports addressed by predictable or disclosed identifiers.
- Not demonstrated
- No real customer export was requested, observed, inferred, or retained. Identifier discovery breadth was not tested.
The download lookup accepted export_id without binding it to the route workspace before file delivery.
External behavior was assessed. Internal source, framework policy composition, and deployment configuration were not reviewed.
Remediation
Resolve the export by workspace_id + export_id, apply the authorization policy before streaming, and return one neutral not-found boundary.
observer + foreign export → 200 + fileobserver + foreign export → 404 + no bodyowner + own export → 200 + fileRetest matrix
| Path | Expected | Observed | Evidence | Recorded result |
|---|---|---|---|---|
| observer · ws_amber → exp_042 · ws_cobalt | 404 · empty body | 404 · empty body | EV-103 | Restored |
| owner · ws_amber → exp_amber_017 | 200 · synthetic CSV | 200 · synthetic CSV | EV-103 | Control held |
Targeted retest closes the recorded condition; it is not a new full assessment of the changed build.
Finding history
- Property break reproduced twiceEV-101 · EV-102Confirmed
- Remediation reported on new buildBuild noteRetest required
- Denied and allowed controls replayedEV-103Closed under retest
Observer closes jobs through a sibling operation
Fix now. The property remains broken while bulk-close accepts observer; the finding cannot be marked closed.
POST /v2/workspaces/{workspace_id}/jobs/{job_id}/closePOST /v2/workspaces/{workspace_id}/jobs/bulk-close- Both jobs begin in in_progress state.
- The UI does not show close actions to observer.
One role rule spans the complete operation family.
Hiding an action in the UI is not the control. Both single and bulk state transitions must enforce the same server-side permission.
EvidenceEV-201
Direct requests crossed the hidden UI boundary.
The observer changed synthetic job state on both handlers even though the client exposed neither action.
EvidenceEV-201 · EV-202
Only the single route received the policy.
The first remediation changed one handler. That is progress, but it does not restore a property defined across the route family.
EvidenceEV-203
The sibling route keeps the finding open.
Single close denied observer and allowed dispatcher. Bulk-close still accepted observer, so the current state is partially remediated.
EvidenceEV-203 · EV-204
Evidence
EV-201 · EV-202 · EV-203 · EV-204
Synthetic request excerptSynthetic evidence
POST /v2/workspaces/ws_amber/jobs/bulk-close
Cookie: session=<REDACTED TEST SESSION>
body: { job_ids: [job_amber_204] }Bounded excerpt · no public verification hash
Synthetic response excerptSynthetic evidence
HTTP/2 202
body: { accepted: 1 }
observed state: job_amber_204 = closedBounded excerpt · no public verification hash
Control observationSynthetic evidence
observer + single close → 403 after fix dispatcher + single close → 202 observer + bulk-close → 202 after fix
Bounded excerpt · no public verification hash
Consequence boundary
- Expected
- Observer receives a denial and both jobs remain in_progress on single and bulk operations.
- Observed
- Before remediation both routes accepted observer. Retest denied the single route, but bulk-close still returned 202 and closed the second synthetic job.
- Demonstrated
- An observer changed owned synthetic job state through a server operation reserved for dispatcher/owner.
- Possible, not demonstrated
- Other sibling workflow operations may enforce the same property inconsistently.
- Not demonstrated
- Only the named close family and owned synthetic jobs were tested. No customer job or external side effect was involved.
Authorization was added to one handler rather than to the shared state-transition policy used by the route family.
Handler behavior supports this contributing condition; source-level control placement was not independently verified.
Remediation
Apply one server-side transition policy to single and bulk operations, verify the current state atomically, then replay every actor × operation control.
observer + single/bulk close → 202 + state changeobserver + single close → 403 · bulk-close → 202observer + every close operation → 403 + unchangedRetest matrix
| Path | Expected | Observed | Evidence | Recorded result |
|---|---|---|---|---|
| observer → jobs/{id}/close | 403 · unchanged | 403 · unchanged | EV-203 | Restored |
| dispatcher → jobs/{id}/close | 202 · closed | 202 · closed | EV-203 | Control held |
| observer → jobs/bulk-close | 403 · unchanged | 202 · closed | EV-204 | Still broken |
Targeted retest closes the recorded condition; it is not a new full assessment of the changed build.
Finding history
- Single and bulk breaks reproducedEV-201 · EV-202Confirmed
- Single-route policy deployedBuild noteRemediation reported
- Route-family retest found residual breakEV-203 · EV-204Partially remediated
Magic link can be consumed twice
Do not close. Replay sequential and concurrent matrices on the named build and retain one allowed-path control.
POST /v2/auth/magic-links/{token}/consume- One synthetic link is issued for test_user_07.
- No real mailbox, token, or session value is retained in this report.
One capability may create one session.
The token reference is a single-use capability. Consumption and session issuance must behave as one atomic decision.
EvidenceEV-301
The same link reference issued a second session.
Two sequential requests both succeeded. Only session references and response metadata were retained.
EvidenceEV-301 · EV-302
An atomic consume change was reported.
The team reports moving single-use state ahead of session issuance. This is remediation input, not observed closure evidence.
Evidence—
The matrix is defined but has not run.
The report keeps the finding open until one allowed consume and sequential/concurrent denied replays produce evidence on the named build.
Evidence—
Evidence
EV-301 · EV-302
Synthetic request excerptSynthetic evidence
POST /v2/auth/magic-links/<SYNTHETIC TOKEN REF>/consume attempt 1 → 201 · session_ref_A attempt 2 → 201 · session_ref_B
Bounded excerpt · no public verification hash
Synthetic response excerptSynthetic evidence
token value: not retained session values: not retained two distinct synthetic session references recorded
Bounded excerpt · no public verification hash
Control observationSynthetic evidence
fresh link + first consume → expected 201 same link + second consume → observed 201 concurrent replay → not tested
Bounded excerpt · no public verification hash
Consequence boundary
- Expected
- The first valid consume creates one session; every later consume fails without creating another session.
- Observed
- Two sequential consume requests against the same synthetic token reference each created a distinct test session.
- Demonstrated
- A single synthetic authentication capability was replayed to create two owned test sessions.
- Possible, not demonstrated
- A copied or delayed link could remain useful after its first successful use.
- Not demonstrated
- Only sequential replay on owned test material was demonstrated. Concurrent race behavior and real mail delivery were not tested.
The consume behavior did not make single-use state visible before issuing the second session.
Atomicity and transaction placement are remediation hypotheses; no source or datastore transaction was observed.
Remediation
Reported fix: mark the link consumed atomically before session issuance and reject every later or concurrent consume.
same link → session A + session Batomic consume before session issuance201 once · later/concurrent attempts deniedRetest matrix
| Path | Expected | Observed | Evidence | Recorded result |
|---|---|---|---|---|
| fresh link → first consume | 201 · one session | Not run | — | Pending |
| same link → sequential replay | denied · zero new sessions | Not run | — | Pending |
| same link → concurrent replay | one success maximum | Not run | — | Pending |
Targeted retest closes the recorded condition; it is not a new full assessment of the changed build.
Finding history
- Sequential replay reproduced twiceEV-301 · EV-302Confirmed
- Atomic consume change reportedBuild noteFixed — not retested
Coverage ledger
15 recorded directions · 12 applicable. Every row keeps its applicability rationale, exact test, evidence, disposition, and limit.
| Direction | Expected property | Applicability | Exact test | Recorded result | Disposition | Limit |
|---|---|---|---|---|---|---|
| IDENT-01Identity and sessions | Session termination invalidates the owned test session. | ApplicableSession endpoints are present. | TC-011Logout then replay the same session reference. | Replay denied. | Held under test | Other devices and long-lived sessions were not assessed. |
| IDENT-04Identity and sessions | Magic link is single use. | ApplicableMagic-link authentication is present. | TC-301Consume one owned synthetic link twice. | Two sessions created.EV-301 · EV-302 | Finding-linked direction | Concurrent replay remains untested. |
| IDENT-06Identity and sessions | Repeated authentication attempts are bounded. | ApplicablePublic authentication route exists. | TC-061Bounded throttling window. | Permission window not granted. | Blocked | Resume after an approved request-rate ceiling. |
| AUTHZ-02Authorization and tenant isolation | Workspace ownership constrains export downloads. | ApplicableMulti-workspace export route is present. | TC-101Cross-workspace identifier substitution with owned actors. | Break reproduced; closed on targeted retest.EV-101 · EV-102 · EV-103 | Finding-linked direction | Closure applies to the named route/build only. |
| AUTHZ-03Authorization and tenant isolation | Role gates apply to every close operation. | ApplicableObserver, dispatcher and owner roles are present. | TC-201Actor × single/bulk operation matrix. | Bulk sibling remains broken.EV-201 · EV-202 · EV-203 · EV-204 | Finding-linked direction | Other workflow families were sampled separately. |
| FLOW-02Workflows and state | Closed transition requires an allowed role and current state. | ApplicableJob state workflow is present. | TC-204Denied/allowed actors across sibling operations. | Partially remediated.EV-203 · EV-204 | Finding-linked direction | No destructive or external job effects were triggered. |
| FLOW-04Workflows and state | Single-use state is atomic. | ApplicableMagic-link consume changes authentication state. | TC-302Sequential replay; concurrent replay planned. | Sequential break reproduced; fix not retested.EV-301 · EV-302 | Finding-linked direction | Concurrency remains unknown. |
| INPUT-03Input and server behavior | Upload type is validated from content and bounded size. | ApplicableSynthetic attachment upload is present. | TC-403Mismatched extension/content and bounded oversized fixture. | Rejected before storage.EV-401 | Held under test | Malware processing and downstream previewers were out of scope. |
| API-02APIs and integrations | Unsigned webhook cannot change a job. | ApplicableSynthetic inbound webhook is present. | TC-502Unsigned and expired synthetic events. | Rejected before state change.EV-501 | Held under test | Provider delivery and replay behavior were not assessed. |
| SERVER-01Input and server behavior | Unhandled identifiers do not disclose stack details. | ApplicableParameterized public routes are present. | TC-601Malformed and unknown synthetic identifiers. | Neutral 404/400 responses. | Held under test | Non-HTTP service errors were not assessed. |
| EXPOSURE-01External exposure | Named surface does not expose backup or debug artifacts. | ApplicablePublic web/API hosts are in scope. | TC-701Known artifact paths and discovered public references. | No artifact reproduced. | Held under test | Observed adjacent hosts remained passive inventory. |
| API-06APIs and integrations | Graph query authorization is enforced. | Not applicableNo graph endpoint or client reference was discovered. | Applicability discovery only. | Not present in frozen surface. | Not applicable | Reassess if a graph endpoint is added. |
| PAY-01Payments | Payment state transitions enforce amount and actor rules. | Not applicableRelayboard synthetic system contains no payment feature. | Applicability discovery only. | No payment surface present. | Not applicable | No conclusion about external billing systems. |
| THIRD-01Third-party effects | External messaging does not accept unauthorized triggers. | ApplicableA production messaging integration is referenced. | TC-801Passive configuration and route review only. | Active delivery excluded by effect ceiling. | Out of scope | Requires separate authority and a synthetic provider sink. |
| SESSION-09Identity and sessions | Session behavior after credential rotation is bounded. | UnresolvedCredential-rotation behavior was not observable externally. | External observation with owned accounts. | No reliable disposition. | Unknown | Needs a controlled rotation event or source/config evidence. |
Held controls
- Condition
- Unsigned and expired events sent to the owned synthetic workspace.
- Observed
- Both were rejected before the synthetic job changed.
- Evidence
- EV-501
- Limit
- Provider-origin delivery, retry, and replay were not assessed.
- Condition
- Owned text fixture declared as image plus bounded oversized fixture.
- Observed
- Both returned a validation response and no stored object reference.
- Evidence
- EV-401
- Limit
- Malware scanning and downstream rendering were outside scope.
Limits and appendices
All systems, names, routes, identifiers, records, timestamps, responses, and outcomes in this public report were created for this clean-room illustration. The sample demonstrates Defence report structure and reasoning, not a customer outcome, certification, or independent validation of Defence.
Limitations and unknowns
External behavior only
No source code, infrastructure-as-code, cloud policy, internal service, or employee workflow was reviewed.
Add a separately scoped internal review if those conclusions are required.Named builds only
Assessment and retest observations apply to the exact builds and conditions recorded in each finding.
Material authorization, routing, identity, or workflow changes reopen affected directions.Rate-limit blocker
The approved effect ceiling did not include the request rate needed for a meaningful throttling test.
Approve a bounded window, maximum rate, stop threshold, and contact.No absolute assurance
Complete applicable coverage records a disposition for every applicable direction in the frozen scope. It does not prove that every vulnerability is absent.
Reassess after material product change or when new authority/evidence changes applicability.Evidence index
| ID | Type / relation | Current build | Timestamp | Handling / lineage |
|---|---|---|---|---|
| EV-101 | Request/response excerptSYN-01 · TC-101 | relayboard-web 2026.08.18.5 | 2026-08-18 10:14 UTC | Session value and body minimizedSynthetic evidence |
| EV-102 | Reproduction controlSYN-01 · TC-102 | relayboard-web 2026.08.18.5 | 2026-08-18 10:22 UTC | Synthetic identifiers onlyDerived from EV-101 |
| EV-103 | Retest matrixSYN-01 · TC-103 | relayboard-web 2026.08.22.3 | 2026-08-22 09:18 UTC | Response bodies minimizedDerived from EV-101 |
| EV-201 | Single-route reproductionSYN-02 · TC-201 | relayboard-web 2026.08.18.5 | 2026-08-18 13:06 UTC | Owned job onlySynthetic evidence |
| EV-202 | Sibling-route reproductionSYN-02 · TC-202 | relayboard-web 2026.08.18.5 | 2026-08-18 13:19 UTC | Owned job onlyDerived from EV-201 |
| EV-203 | Single-route retestSYN-02 · TC-203 | relayboard-web 2026.08.22.3 | 2026-08-22 10:02 UTC | Owned roles and jobsDerived from EV-201 |
| EV-204 | Sibling-route retestSYN-02 · TC-204 | relayboard-web 2026.08.22.3 | 2026-08-22 10:11 UTC | Owned roles and jobsDerived from EV-202 |
| EV-301 | Sequential replay excerptSYN-03 · TC-301 | relayboard-web 2026.08.18.5 | 2026-08-19 08:44 UTC | Token and sessions not retainedSynthetic evidence |
| EV-302 | Reproduction controlSYN-03 · TC-302 | relayboard-web 2026.08.18.5 | 2026-08-19 08:51 UTC | References onlyDerived from EV-301 |
| EV-401 | Upload controlINPUT-03 · TC-403 | relayboard-web 2026.08.18.5 | 2026-08-19 11:05 UTC | Synthetic fixtures onlySynthetic evidence |
| EV-501 | Webhook controlAPI-02 · TC-502 | relayboard-web 2026.08.18.5 | 2026-08-19 12:27 UTC | Synthetic event IDsSynthetic evidence |
Bounded excerpt · no public verification hash
Methodology registry
- Defence external review model1.0
- Scope, property graph, evidence, dispositions, and terminal honesty.
- OWASP Web Security Testing Guide4.2
- Web testing direction and method reference.
- OWASP API Security Top 102023
- API authorization, resource, flow, and inventory lenses.
- HackTrickssnapshot 2026-08-18
- Technique prompts; never evidence by itself.
Revision history
- v0.9Assessment draft
Initial findings and coverage ledger.
- v1.0Final illustrative report
Remediation inputs, targeted retest, and current-state projection added without overwriting initial evidence.