THE DOMAIN WAS REAL. THE AUTHORITY WASN'T.
Revolut says fraudulent information requests arrived through a legitimate government-agency email domain and resulted in customer data being disclosed to an unauthorised third party. I used to run a bank and built an earlier version of a regulator-as-user product. This incident made me revise one of the assumptions behind it.
NO EXOTIC FAILURE IS NEEDED TO EXPLAIN THIS.
A convincing piece of evidence — the channel — acquired too much operational authority before the human, current capacity, mandate and scope were fully resolved.
Public facts, company statements, secondary reporting and my inferences are kept separate below.
The hotline
WHAT THIS PAGE IS ACTUALLY ABOUTThe earlier version I actually built
ARIVAL ≤2023▚ WHAT WE WERE TRYING TO FIX
At Arival, I treated the regulator as a product segment rather than an external nuisance. An agency could exist as an entity, with named human representatives as sub-users. Bank-account functionality was disabled; the point was structured supervisory interaction.
- Named regulator users rather than anonymous inbox traffic.
- Read-only compliance views rather than endless PDF ping-pong.
- Contextual questions around a client or transaction.
- Session telemetry: logins, pages viewed, time spent, reports opened.
- A product/segment owner focused on regulator requests and UX.
▚ WHAT AGED WELL — AND WHAT DID NOT
Survived: regulatory interaction is a product problem: actors, objects, states, evidence, latency and auditability all matter.
Did not survive: using the working government email as the bootstrap root of trust. A legitimate domain can be evidence about the channel without proving the current human, their capacity or their mandate.
2026 revision: Regulator-as-user → authority-as-preverified-principal, with scoped virtual views and explicit mandate objects.
MODEL CLAIM this reading is my inference — not Revolut's published root-cause language.
My first fix still leaked
R002 · THE USEFUL EMBARRASSMENTI initially allowed a “minimum dataset” before principal verification.
That sounded pragmatic: give less now, verify more later. It was also the same failure class with a smaller payload. Once an address, phone number, ID fragment or account detail leaves the bank, it is not provisional in any meaningful sense.
Government-domain match → provisional minimum disclosure while identity resolves.
Government-domain match → HOLD. Preserve / prepare / escalate internally. packet_out = null until principal + capacity + mandate + scope pass.
A case may remain provisional. An outbound packet may not.
What I would ship on Monday morning
BEFORE A PLATFORM REWRITE · SPEC · PROPOSEDINDEPENDENT CALLBACK
Out-of-band verification via a number sourced independently of the request.
REQUESTER REGISTRY
Named principals + current capacity. Domain membership is insufficient.
HOLD
While authority resolves: preserve, prepare, restrict deletion, escalate. Release zero PII.
DUAL CONTROL
Second human for passports, selfies and broad transaction-history releases.
EVIDENCE PACKET
Canonicalise → hash → sign → timestamp → bind to rule version and mandate object.
The five authority gates
BEFORE IRREVERSIBLE DISCLOSURECHANNEL
Where did the message travel? Necessary evidence, never sufficient authority.
PRINCIPAL
Who is the named human/system? Verify independently.
CAPACITY
Do they currently represent the agency in the relevant role?
MANDATE
What lawful power applies to this case, purpose and jurisdiction?
SCOPE
Which subjects, fields and time range may leave?
Runtime + tests
REFERENCE IMPLEMENTATION, NOT DEPLOYMENT CLAIM · SPEC · PROPOSED{
"request_id": "DW-2026-09-14-0041",
"channel_evidence": { "type": "gov_domain_email", "status": "pass", "role": "evidence_only" },
"principal": { "name": null, "verified_out_of_band": false },
"capacity": { "agency_id": null, "current": "unknown" },
"mandate": { "legal_basis": null, "case_id": null, "jurisdiction": null },
"scope": { "subjects": [], "fields": [], "time_range": null },
"state": "HOLD",
"packet_out": null,
"ai_override": false
}DATA_OUT := channel_evidence.valid AND principal.verified AND capacity.current AND mandate.valid AND scope.non_empty AND required_human_approvals.complete if irreversible(action): deferred_controls(action) = ∅ HOLD.permits = [ preserve, prepare_internal, restrict_deletion, escalate ] HOLD.forbids = [ release_pii, export_kyc, disclose_tx_history ] ai_override = false
// choose a trajectory
These are reference-model assertions. They become evidence only when the same invariants are enforced and regression-tested in implementation. SPEC · PROPOSED
Legitimate agency domain
Revolut confirmed fraudulent requests sent from a legitimate government-agency email domain.
Data disclosure
Revolut confirmed sensitive customer information was disclosed to an unauthorised third party.
Systems + funds
Revolut said its systems and customer funds were unaffected.
Data categories
TechCrunch says identity/contact details and ID document copies were affected; selfies, statements and transaction histories may also have been included.
Authority plumbing
My model: channel evidence became operational permission too early. This is not Revolut's published root-cause language.
LC03
A design response derived from LC01/LC02 — not a deployed Revolut or Arival control.
Adversarial Compliance Lab
WEIRD PROPOSAL, DELIBERATELY · SPEC · PROPOSEDTrain the control against people who know how controls get gamed.
A synthetic disclosure desk. Professional red-teamers first. Then, case-by-case and under ordinary paid contracts, people with lived experience of fraud or social engineering generating attack paths a conventional compliance exercise may never imagine: urgency theatre, false capacity cues, scope inflation, the “helpful shortcut” after a refusal. No production PII. The product is not cheap labour. The product is adversarial knowledge.
Baseline: security, fraud and compliance specialists.
Post-conviction / post-release experts, paid normally, synthetic environment only.
Custodial setting only later, if HMPPS + ethics + security design make sense.
One research line, several artifacts
NOT TEN UNRELATED DEMOSRevision ledger
THE PAGE EXPOSES ITS OWN SCARSBreak the model, not the prose
THE STRONGEST RESPONSE IS A REVISION EVENTBreak the model, not the prose.
If you can design a synthetic request that crosses DATA OUT without complete principal + capacity + mandate + scope, the strongest response is not a defensive paragraph. It is a signed revision event and a new regression test.
OPEN THE SHORT NEWS VERSION ↗Honest boundary. Personal research note by an outsider. Not affiliated with Revolut Ltd; not Revolut's root-cause language; not a description of Arival's or Revolut's current controls. Sources are public reporting and company statements, separated from my inferences throughout. Nothing on this page is legal advice.