Security

Security

A dated record of how we test ReferralFinderX’s security, newest first. Each time we run a new test or publish a new document, we add it here with its date, so anyone reviewing ReferralFinderX can follow our security practices over time.

Last updated

To report a security problem, or to ask about anything on this page, email security@referralfinderx.com. The protections built into the app are listed in the Security section of our Privacy Policy.

Timeline Newest first

  1. Every change to our API is now attacked before we release it, and attacks on the live system found no server error and no wrong access.

    Every change to our API now meets an attack on its routes, and a change cannot be released until that attack finds no server error. We then attacked the live system itself, in test clinics set up for it, with 13,797 attack requests, and not one was answered with a server error. In the part that called the API as 14 kinds of user across two test clinics, no request was let through that the user’s role should refuse.

    What is new in this release

    The protections that came with this release:

    • Every change attacked before we release itA tool sends unexpected input to our API’s routes, signed in as a clinic owner and as a lite user, against a database built the way the live one is. It covers every route except the few that end your own sessions or need our sign-in service. If any request is answered with a server error, the check fails, and the change is held: it cannot reach the live system until every check passes.
    • Every number pushed past its limitBefore that attack, a separate check sends every number a read route accepts past the largest value our database can hold. None may be answered with a server error, or the check fails.
    • No passwords or keys in our code’s historyEvery change is also checked by a scan of the API’s whole history for passwords and keys written into the code by mistake, beside the check of our libraries against published security advisories that was already in place.
    • Steady under heavy useWe capped a cache inside our API so its memory stays within a fixed size however many different searches people run.

    How we ran it

    How the live attacks were set up:

    • The live system, in test clinicsWe attacked the live API itself, not a copy. Every signed-in attack used accounts in test clinics we set up for it, holding test data only; the attacks changed nothing outside those clinics, and no real email was sent. Our normal request limits stayed on, so 264 requests were told to slow down, as anyone’s would be.
    • First, an attack that only readsEvery number pushed past its limit, then unexpected input sent to 76 of the API’s 78 read routes, signed in as a clinic owner.
    • Then 14 kinds of user, twiceNext, a walk through the API as 14 kinds of user: signed out; a clinic owner with and without two-step sign-in; advanced, basic and lite users; users whose team limits what they can do; a user on no team; a colleague in the same clinic; and four users of a second test clinic aimed at the first clinic’s records. For each request we wrote down first what that user should be allowed to do, and the walk compared every answer with it. It also looked through every answer for records from any clinic outside the two test clinics. We ran the walk twice.
    • Last, changing thingsInside one test clinic, as its owner, unexpected input sent to 98 of the API’s 112 routes that add, change or delete something.

    The scans

    Attack requests each part sent, and how many server errors it found. Bars are to scale.

    PartRequestsShare of the largestFound
    Changing thingsRoutes that add, change or delete, inside one test clinic, as its owner4,5890
    Reading onlyEvery number past its limit, then unexpected input to the read routes, as a clinic owner4,5650
    Second walk14 kinds of user across two test clinics2,3370
    First walkThe same 14 kinds of user, earlier the same day2,3060

    What it found, and what it left out

    No server error in any of the 13,797 requests. In both walks, no request was let through that the user should have been refused, including the 1,270 requests in which a user of the second clinic aimed at the first clinic’s records, and no answer showed records from any clinic outside the two test clinics. A few answers differed from the walk’s expectation the other way, a refusal where an answer was expected; none let anyone in.

    Left out on the live system: the routes that send real email (inviting and managing users, support tickets, the website’s forms and password resets), the routes that sign you out everywhere, changing your own password, resetting two-step sign-in, and the desktop demo’s sign-up. ReferralFinderX’s own tools, support’s console and the data hygiene engine’s routes, were checked only to be sure clinic users are refused. Demo visitors, and accounts that are held, closed, disabled or signed out by force, were not part of these live runs; they were tested on our test copy before this release.

  2. Setting a new password now signs you out on your other devices.

    When you set a new password, including through “Forgot password”, our API now refuses every other session on your account that started before that moment, and we also ask our sign-in service to end those sessions. The device you are using stays signed in.

    What you will notice

    After you set a new password, any other computer or phone signed in to your account asks you to sign in again. If the app cannot reach us to finish that step, it tells you in plain words that your other devices may stay signed in, and still lets you in, because your new password is already set.

    How we checked it

    Before it could ship, the change had to pass checks written to fail on the previous version and pass on this one. An independent review attacked the plan before it was built, and every point it raised was fixed or ruled on before release.

  3. More suggestions now wait for a person to decide, and attack scans of this release found nothing at any level.

    With this release, more of the data hygiene engine’s suggestions about an office’s website and group wait in support’s list for a person to decide, each with a plain sentence saying why. Before release, we attacked a test copy of it with ZAP, an open-source security scanner. The scans reached 185 of the API’s 185 routes, sent 207,993 attack requests and found nothing: no finding at the High, Medium, Low or Informational level.

    Scan record

    Date
    20 Oct 2026
    Target
    Test copy of this release
    Tool
    ZAP 2.17
    Signed in
    As owner and support
    Attack rules
    52 of 52, finished in each of the 2 API scans
    Requests
    207,993
    Routes reached
    185 of 185
    Alert filters
    None
    Server errors
    0 unplanned
    API scan time
    30 min

    Findings at any level 0

    Findings by level

    • 0HighCould expose data
    • 0MediumWeakens a defence
    • 0LowMinor weakness
    • 0InformationalWorth knowing

    What is new in this release

    The protections that came with this release:

    • A suggestion for review names no groupThis release adds new kinds of suggestion that a person in support must decide on. Our API refuses any of them that names a practice or group, so accepting one can never file an office under a group by itself. In this release’s attack scans, not one such request was stored.
    • A way back that keeps people’s decisionsIf this release’s database change ever has to be undone, a suggestion a person has already decided keeps its decision, who made it, when, and their note; only one still waiting for a decision may be set aside. Every row the undo touches is written to a log first, so the change can be put back exactly as it was.
    • Trusted certificates brought up to dateEvery change to our API must pass a check of the libraries it uses against published security advisories. When a new advisory came out for the list of trusted certificates our API uses to check the servers it connects to, that check held this release until we updated the list, the same day.

    How we checked it

    Each change had to pass checks written for it, and the release was held until every check a release must pass had passed. An independent review attacked the plan before it was built and the finished release before it shipped, and every point it raised was fixed or ruled on before release. The way back for the database change was first tried on a copy: we undid the change and put it back, and the data came back the same, byte for byte.

    How we ran it

    How the scans were set up:

    • A test copy, not the live systemWe scanned this release’s code on a copy running on our own computer with sample data only. No attack request reached the live system, and no real email was sent.
    • Signed in as owner and supportThe API scans signed in as a clinic owner with two-step sign-in. The tools only ReferralFinderX support can use, the list of suggestions among them, were scanned signed in as a support account with a fresh code.
    • No filtered resultsNo result was filtered out or marked as accepted. The only server error was a planned “not available” answer from the Alpha application form, whose mail is switched off on the test copy.

    The scans

    Attack requests each scan sent, and how many findings it raised at any level. Bars are to scale.

    ScanRequestsShare of the largestFound
    Owner and supportThe API, signed in as a clinic owner, with support’s tools signed in as a support account203,8510
    Follow-up scanThe route the data hygiene engine reports back on, scanned again on its own after the main scan3,5680
    Website and web appEvery page opened in a real browser, looking for script planted in a page5740

    Routes reached

    This release adds no route: the API still has 185, and the main API scan reached all 185. To the route the data hygiene engine reports back on, the follow-up scan then sent the one kind of report from the engine that the main scan had not sent; the report was accepted, then attacked.

    Actions that work only once, such as a decision on a suggestion, were again given a fresh item for each attack request, so the attacks reached the code behind them. In the API scans, a separate check also looked through every response, 209,000 in all, for a marker planted in another clinic’s records, and found none.

    What it found, and what it left out

    Nothing, at any level: no High, Medium, Low or Informational finding in any of the scans.

    The scans ran on the release’s final code, apart from the update to the list of trusted certificates, which came after them and changes no route. Attack requests on the new details in a clinic’s request went out as a clinic where these suggestions are switched off, so they met every check on those details; for a clinic where they are switched on, the scan sent only ordinary requests.

    As a clinic owner, this release’s scans signed in with two-step sign-in only; they did not repeat the earlier password-only, demo-visitor and closed-clinic scans. The website and web app were scanned in a real browser without signing in, the website as it was before this entry. Scans as the other kinds of clinic user, and of the web app signed in, are part of what’s next.

  4. A clinic can now tell us an office’s website and its group, and attack scans of this release found nothing at any level.

    With this release, a clinic that sends an update or adds an office can also give the office’s website and the practice or health system it belongs to. Before release, we attacked a test copy of it with ZAP, an open-source security scanner. The scans reached 185 of the API’s 185 routes, including every new one, sent 188,068 attack requests and found nothing: no finding at the High, Medium, Low or Informational level.

    Scan record

    Date
    20 Oct 2026
    Target
    Test copy of this release
    Tool
    ZAP 2.17
    Signed in
    As owner and support
    Attack rules
    52 of 52, finished in the one API scan
    Requests
    188,068
    Routes reached
    185 of 185
    Alert filters
    None
    Server errors
    0 unplanned
    API scan time
    28 min

    Findings at any level 0

    Findings by level

    • 0HighCould expose data
    • 0MediumWeakens a defence
    • 0LowMinor weakness
    • 0InformationalWorth knowing

    What is new in this release

    The protections that came with this release:

    • One rule for every web addressEvery website a clinic sends us, for an office or for the group it belongs to, passes the same check. If it has no https:// in front, we add it; then it must be an ordinary web address with a real host name, no user name or password in it, and at most 300 characters. Anything else is refused with a plain message that names the field, never what was typed.
    • Group details checked like everything typedA group’s name passes the same checks as text a person types: nothing shaped like web-page code, or that looks like patient information, is accepted. A clinic can name only one of its own offices as another site of the same group.
    • Narrow new access for the engineSo the data hygiene engine can file an office under its practice or group, its database accounts were given only what that needs: they may read the names of groups and practices, fill in an office’s practice or group where none is filed, and add records marked as their own. They still may never delete anything.
    • The database refuses to overwriteThe database itself refuses any change by the engine’s account that would replace a practice or group already filed, and lets it clear one only when it is undoing a change our records show it made.
    • Suggestions wait behind support’s locksSuggestions that need a person wait in a new list in our support console. It opens only to a support account, behind the same locks as support’s other console tools, with its own limit on requests a minute, and every decision is written to our tamper-evident access log.
    • Quick when the list is longA clinic’s list of pending requests is now read with a few database reads for the whole list, not several for each request in it, so it stays quick when the list is long. Under the heavy load of this release’s attack scans, our API never once answered that it was too busy.

    How we checked it

    Each change had to pass checks written for it, and the release was held until every check a release must pass had passed. An independent review attacked the plan before it was built and the finished release before it shipped, and every point it raised was dealt with before release. The engine’s new database access was first tried on a copy, with checks that each account could do only what it should, and that undoing it gives back exactly the permissions there were before.

    How we ran it

    How the scans were set up:

    • A test copy, not the live systemWe scanned this release’s code on a copy running on our own computer with sample data only. No attack request reached the live system, and no real email was sent.
    • Signed in as owner and supportThe API scan signed in as a clinic owner with two-step sign-in. The tools only ReferralFinderX support can use, the new list among them, were scanned signed in as a support account with a fresh code.
    • No filtered resultsNo result was filtered out or marked as accepted. The only server error was a planned “not available” answer from the Alpha application form, whose mail is switched off on the test copy.

    The scans

    Attack requests each scan sent, and how many findings it raised at any level. Bars are to scale.

    ScanRequestsShare of the largestFound
    Owner and supportThe API, signed in as a clinic owner, with support’s tools signed in as a support account187,4940
    Website and web appEvery page opened in a real browser, looking for script planted in a page5740

    Routes reached

    The API now has 185 routes, 5 more than on 19 October: the new list in support’s console, the three actions taken on it, and the route the data hygiene engine uses to report back on a suggestion. The scan reached all 185.

    Actions that work only once, such as a decision on a suggestion, were given a fresh item for each attack request, so the attacks reached the code behind them. In the API scan, a separate check also looked through every response, 189,050 in all, for a marker planted in another clinic’s records, and found none.

    What it found, and what it left out

    Nothing, at any level: no High, Medium, Low or Informational finding in any of the scans. We got there by fixing what earlier test scans of this release pointed to, in our code and in the scan’s own set-up, then scanning again, never by filtering results.

    The scans ran on the release’s final code. Attack requests on the new details in a clinic’s request went out as a clinic where these suggestions are switched off, so they met every check on those details; for a clinic where they are switched on, the scan sent only ordinary requests.

    As a clinic owner, this release’s scan signed in with two-step sign-in only; it did not repeat the earlier password-only, demo-visitor and closed-clinic scans. The website and web app were scanned in a real browser without signing in, the website as it was before this entry. Scans as the other kinds of clinic user, and of the web app signed in, are part of what’s next.

  5. Our server now stays responsive when requests overlap, and attack scans of this release found nothing at any level.

    This release hardens how our server handles requests that arrive at the same time, and adds a tool ReferralFinderX support uses to check a new clinic’s office list. Before release, we attacked a test copy of it with ZAP, an open-source security scanner. The scans reached 180 of the API’s 180 routes, including the new one, sent 168,618 attack requests and found nothing: no finding at the High, Medium, Low or Informational level.

    Scan record

    Date
    18 Oct 2026
    Target
    Test copy of this release
    Tool
    ZAP 2.17
    Signed in
    As owner and support
    Attack rules
    52 of 52, finished in the one API scan
    Requests
    168,618
    Routes reached
    180 of 180
    Alert filters
    None
    Server errors
    0 unplanned
    API scan time
    51 min

    Findings at any level 0

    Findings by level

    • 0HighCould expose data
    • 0MediumWeakens a defence
    • 0LowMinor weakness
    • 0InformationalWorth knowing

    What is new in this release

    The protections that came with this release:

    • Steady when requests overlapWhen requests from our background services arrive at the same moment, each now waits its turn without holding up anyone else’s, and one our API turns down lets go of what it held before it answers. The tools ReferralFinderX support uses to set up a new clinic now wait their turn the same way.
    • A new support tool behind the same locksThe new tool support uses to start checking a new clinic’s office list opens only to a support account, and needs a written reason, a fresh code from support’s authenticator app and a second, confirming request.

    How we checked it

    Each change had to pass checks written for it, and the release was held until every check a release must pass had passed. The checks written for the hardening send overlapping requests to a real copy of our server and its database, and pass only when each request is answered within seconds and other requests are answered in the meantime. An independent review attacked the plan before it was built and the new tools before they shipped, and every point it raised was dealt with before release.

    How we ran it

    How the scans were set up:

    • A test copy, not the live systemWe scanned this release’s code on a copy running on our own computer with sample data only. No attack request reached the live system, and no real email was sent.
    • Signed in as owner and supportThe API scan signed in as a clinic owner with two-step sign-in. The tools only ReferralFinderX support can use, the new one among them, were scanned signed in as a support account with a fresh code.
    • No filtered resultsNo result was filtered out or marked as accepted. The only server error was a planned “not available” answer from the Alpha application form, whose mail is switched off on the test copy.

    The scans

    Attack requests each scan sent, and how many findings it raised at any level. Bars are to scale.

    ScanRequestsShare of the largestFound
    Owner and supportThe API, signed in as a clinic owner, with support’s tools signed in as a support account167,5540
    Website and web appTwo scans of every page in a real browser, looking for script planted in a page; the second included this page1,0640

    Routes reached

    The API now has 180 routes, 1 more than on 18 October: the new support tool. The scan reached all 180.

    Starting the check of a clinic’s list needs a confirming request that works only once, so each attack request on it was given a fresh test case with its own confirmation, and the attacks could reach the code behind it. In the API scan, a separate check also looked through every response, 169,150 in all, for a marker planted in another clinic’s records, and found none.

    What it found, and what it left out

    Nothing, at any level: no High, Medium, Low or Informational finding in any of the scans.

    The API scan ran before the release’s last small changes, which only reword a few messages; the second website scan ran on the web app exactly as released.

    As a clinic owner, this release’s scan signed in with two-step sign-in only; it did not repeat the earlier password-only, demo-visitor and closed-clinic scans. The website and web app were scanned in a real browser without signing in. Scans as the other kinds of clinic user, and of the web app signed in, are part of what’s next.

  6. Setting up a new clinic: its office list is screened before anything is kept, and attack scans found nothing at any level.

    This release lets ReferralFinderX support take in a new clinic’s own list of its offices while setting the clinic up. Before writing this entry, we attacked a test copy of the release with ZAP, an open-source security scanner. The scans reached 179 of the API’s 179 routes, including every new one, sent 401,951 attack requests and found nothing: no finding at the High, Medium, Low or Informational level.

    Scan record

    Date
    18 Oct 2026
    Target
    Test copy of this release
    Tool
    ZAP 2.17
    Signed in
    As owner, support and a closed clinic
    Attack rules
    52 of 52, finished in each of the 9 API scans
    Requests
    401,951
    Routes reached
    179 of 179
    Alert filters
    None
    API scan time
    107 min

    Findings at any level 0

    Findings by level

    • 0HighCould expose data
    • 0MediumWeakens a defence
    • 0LowMinor weakness
    • 0InformationalWorth knowing

    What is new in this release

    The protections that came with this release:

    • A clinic’s list is screened twiceWhen ReferralFinderX support takes in a new clinic’s list, it is checked for anything that looks like patient information on the computer it is opened on, before anything is sent, and again by our API, row by row, before any row is stored. A refusal names only the row, never what it holds.
    • Notes are never sentOnly the columns we need are taken from a list, and every other column is left out before anything is sent. A notes or comments column never leaves the computer the list is opened on, and our API refuses any list that carries one.
    • Limits on size and paceA list may hold at most 5,000 rows, 200 characters in a cell and 1 MB in all, and each person may send one at most four times a minute. Taking in or replacing a list also needs a written reason and a fresh code from support’s authenticator app.
    • Kept to that clinicOffices from a clinic’s list are added only to that clinic’s own directory, never to our shared directory or to another clinic’s. Our log of each list holds its counts, never a row.
    • A written reason for the engine’s switchTurning the data hygiene engine’s checks on or off for a clinic now also needs a written reason, and the reason is written into our tamper-evident access log with the change. The switch of a clinic we have closed cannot be turned at all.
    • Closed means closedWhen we close a clinic we set up, every request from its users’ accounts is refused, and they now read plainly that ReferralFinderX is closed for their organisation. This release’s scans attacked that refusal, as described below.

    How we checked it

    Each new protection had to pass checks written for it, and the release was held until every check a release must pass had passed. An independent review attacked the plan before it was built and the finished release before it shipped, and every point it raised was dealt with before release. We also took a made-up clinic list through the new steps on a test copy and confirmed that its notes were never sent.

    How we ran it

    How the scans were set up:

    • A test copy, not the live systemWe scanned this release’s code on a copy running on our own computer with sample data only. No attack request reached the live system, and no real email was sent.
    • Signed in as owner, support and a closed clinicTwo scans signed in as a clinic owner with two-step sign-in: one with new clinics set up the earlier way, one with the new steps. The tools only ReferralFinderX support can use, the new list tools among them, were scanned signed in as a support account with a fresh code. Another scan signed in as the account of a clinic we had closed.
    • No filtered resultsNo result was filtered out or marked as accepted.

    The scans

    Attack requests each scan sent, and how many findings it raised at any level. Bars are to scale.

    ScanRequestsShare of the largestFound
    Owner, two-step sign-inThe API, signed in as a clinic owner, with new clinics set up the earlier way140,9240
    Owner, new stepsThe same owner, with new clinics set up the new way140,9210
    Closed clinicThe API, signed in as the account of a clinic we had closed30,4070
    Follow-up scansSix scans of a few routes each, after the main scans88,6310
    Website and web appTwo scans of every page in a real browser, looking for script planted in a page; the second included this page1,0680

    Routes reached

    The API now has 179 routes, 3 more than on 17 October, all of them tools support uses to set up a new clinic. Together, the scans reached all 179.

    Signed in as the account of a clinic we had closed, the scanner tried the 17 routes a clinic’s users work with 30,221 times, and every attempt was refused. In each API scan, a separate check also looked through every response, 404,050 in all, for a marker planted in another clinic’s records, and found none.

    What it found, and what it left out

    Nothing, at any level: no High, Medium, Low or Informational finding in any of the scans. Where a first scan pointed to something to improve, we changed the code and scanned those routes again, never filtering results.

    The main scans ran before the API’s last small changes: we scanned the routes one of them touches again, and the other only adds one name to our list of specialty names.

    As a clinic owner, these scans signed in with two-step sign-in only; they did not repeat the password-only and demo-visitor scans of 17 October. Follow-up scans of the same test copy also attacked replacing a list that is already kept, and the preview that runs before a new clinic’s directory is first filled. The website and web app were scanned in a real browser without signing in. Scans as the other kinds of clinic user, and of the web app signed in, are part of what’s next.

  7. ReferralFinderX 1.0 Avocet: new tools, each behind its own lock, and attack scans that found nothing at any level.

    ReferralFinderX 1.0 Avocet is our first named release. It brings our new design, live since 16 October, and, since 17 October, the data hygiene engine checking update requests for the clinics where it is switched on. Before writing this entry, we attacked a test copy of the release that is now live with ZAP, an open-source security scanner. The scans reached 176 of the API’s 176 routes, including every route the data hygiene engine uses, sent 319,781 attack requests and found nothing: no finding at the High, Medium, Low or Informational level.

    Scan record

    Date
    17 Oct 2026
    Target
    Test copy of this release
    Tool
    ZAP 2.17
    Signed in
    As owner, support and demo visitor
    Attack rules
    52 of 52, finished in each of the 3 API scans
    Requests
    319,781
    Routes reached
    176 of 176
    Alert filters
    None
    Server errors
    0 unplanned
    API scan time
    80 min

    Findings at any level 0

    Findings by level

    • 0HighCould expose data
    • 0MediumWeakens a defence
    • 0LowMinor weakness
    • 0InformationalWorth knowing

    What is new in this release

    The protections that came with this release:

    • The engine has its own locked accountThe data hygiene engine signs its work with an account of its own in each clinic. That account can never sign in, no clinic user can change it, and the routes the engine uses answer only to its own secret key.
    • Nothing that names the clinic or its peopleWhen the engine checks a request, it is never given the clinic’s name, its people or their accounts.
    • The engine’s answers are checked tooEvery value and quote the engine sends back passes the same checks as text a person types. Anything shaped like web-page code, or that looks like patient information, is refused before it is stored, and the refusal never repeats the text.
    • Switched on only by us, with a fresh codeWhether the engine checks a clinic’s requests is a switch only ReferralFinderX support can turn, and only after entering a fresh code from their authenticator app. Every change of the switch, and every attempt by a support account, refused or not, is written to our tamper-evident access log.
    • Read-only where we only readWhere our API reads our shared directory, it signs in with an account that can read only the tables it needs, under a row rule for each table, and cannot write anything. The API also opens each of those connections read-only, refuses any statement that is not a read, and lets only the parts of the API that need it use it.
    • Narrow write access, with a record of every changeThe engine’s own database account may change only the listing details it checks and add records of its own, may never delete anything, and cannot step around the database’s row rules. Every change it makes is recorded in the directory’s audit trail with a line that can undo it, and the engine and our API’s directory tools take the same lock, so they never write at the same time.
    • New clinics are set up behind layered locksThe tools ReferralFinderX support uses to set up a new clinic open only after a password, an authenticator code, a passkey and a separate access check. Steps that cannot be undone also need a fresh code and a second, confirming request. A new clinic’s users cannot sign in until support switches the clinic on.

    How we checked it

    Each new protection had to pass checks written for it, and the release was held until every check a release must pass had passed. Before release, an independent review attacked the engine’s changes, and every point it raised was dealt with before release. The attack scans below then ran on a copy of exactly the code that is live.

    How we ran it

    How the scans were set up:

    • A test copy, not the live systemWe scanned the same code the live API runs, on a copy running on our own computer with sample data only. No attack request reached the live system, and no real email was sent.
    • Signed in as owner, support and demo visitorOne scan signed in as a clinic owner with a password only, another with two-step sign-in, and another as a demo visitor who may only look. The tools only ReferralFinderX support can use, the engine’s switch among them, were scanned signed in as a support account.
    • No filtered resultsNo result was filtered out or marked as accepted. The only server errors were planned “not available” answers: from the Alpha application form, whose mail is switched off on the test copy, and in the demo-visitor scan from the password reset and the desktop demo form, which were switched off for that scan.

    The scans

    Attack requests each scan sent, and how many findings it raised at any level. Bars are to scale.

    ScanRequestsShare of the largestFound
    Owner, password onlyThe API, signed in as a clinic owner without two-step sign-in113,9970
    Owner, two-step sign-inThe same owner, with two-step sign-in115,5080
    Demo visitorThe API, as a visitor who may only look89,7380
    Website and web appEvery page opened in a real browser, looking for script planted in a page5380

    Routes reached

    The API now has 176 routes, 30 more than on 13 October. Each owner scan reached 176 of them, among them every route the data hygiene engine uses, the switch that turns its checks on, and the tools support uses to set up a new clinic.

    Actions that work only once, such as a decision on a review list, were given a fresh item for each attack request, so the attacks reached the code behind it rather than being turned away as already done.

    Signed in as a demo visitor, the scanner tried to change data 30,618 times, and none was accepted. In each API scan, a separate check also looked through every response, 322,750 in all, for a marker planted in another clinic’s records, and found none.

    What it found, and what it left out

    Nothing, at any level: no High, Medium, Low or Informational finding in any of the scans. We got there by fixing in the code what an earlier test scan of this release pointed to, then scanning again, never by filtering results.

    The website and web app were scanned in a real browser without signing in. Scans as the other kinds of clinic user, and of the web app signed in, are part of what’s next.

  8. Every route in our API reached, and nothing found at any level.

    We used ZAP, an open-source security scanner, to attack a test copy of the API version that is now live. For the first time, the scans reached all 146 of the API’s routes, including the tools only ReferralFinderX support can use and the password reset. Four scans, three of the API and one of the website and web app, sent 267,108 attack requests and found nothing: no finding at the High, Medium, Low or Informational level.

    Scan record

    Date
    13 Oct 2026
    Target
    Test copy of the live API
    Tool
    ZAP 2.17
    Signed in
    As owner, support and demo visitor
    Attack rules
    52 of 52, finished in each of the 3 API scans
    Requests
    267,108
    Routes reached
    146 of 146
    Alert filters
    None
    Server errors
    0 unplanned
    API scan time
    67 min

    Findings at any level 0

    Findings by level

    • 0HighCould expose data
    • 0MediumWeakens a defence
    • 0LowMinor weakness
    • 0InformationalWorth knowing

    How we ran it

    How the scans were set up:

    • A test copy, not the live systemWe scanned the same code the live API runs, on a copy running on our own computer with sample data only. No request reached the live system, and no real email was sent.
    • Signed in as owner and as supportOne scan signed in as a clinic owner with a password only, another with two-step sign-in, and a third as a demo visitor who may only look. The tools only ReferralFinderX support can use were scanned signed in as a support account, and the one action only a basic clinic user may take was scanned signed in as a basic clinic user.
    • No filtered resultsNo result was filtered out or marked as accepted. The only server errors were planned “not available” answers: from the Alpha application form, whose mail is switched off on the test copy, and in the demo-visitor scan from the password reset and the desktop demo form, which were switched off for that scan.

    The scans

    Attack requests each scan sent, and how many findings it raised at any level. Bars are to scale.

    ScanRequestsShare of the largestFound
    Owner, password onlyThe API, signed in as a clinic owner without two-step sign-in95,8350
    Owner, two-step sign-inThe same owner, with two-step sign-in89,4270
    Demo visitorThe API, as a visitor who may only look81,3320
    Website and web appEvery page opened in a real browser, looking for script planted in a page5140

    Routes reached

    A route is one thing the API can be asked to do, such as listing offices or saving a note. A route counts as reached when a request got through to the code behind it, rather than being turned away at the door. Each owner scan reached all 146.

    In each owner scan, attack requests got through to 140 of the 146: on 114 of them dozens to thousands of times, on 26 only a handful, because those actions delete something or work only once. The other 6 were reached only by the scanner’s first, ordinary request: three that delete an item, where that first request deleted it, and three one-time support steps, which turned every later request away, as designed.

    In each API scan, a separate check also looked through every response, 269,000 in all, for a marker planted in another clinic’s records, and found none.

    What it found, and what it left out

    Nothing, at any level: no High, Medium, Low or Informational finding in any of the four scans.

    The password reset was attacked for the first time. The test copy used a stand-in for the human check that protects the reset form, so the scanner could get past it. The website and web app, this page included, were scanned in a real browser without signing in. Scans as the other kinds of clinic user, and of the web app signed in, are part of what’s next.

  9. Before this update went live, attack scans found nothing at any level.

    Before releasing this update, we attacked a test copy of it with ZAP, an open-source security scanner. Four scans covered the API, signed in three different ways, and the website and web app. Together they sent 252,151 attack requests and found nothing: no finding at the High, Medium, Low or Informational level.

    Scan record

    Date
    12 Oct 2026
    Target
    Test copy of this release
    Tool
    ZAP 2.17
    Signed in
    As owner and demo visitor
    Attack rules
    52 of 52, finished in each of the 3 API scans
    Requests
    252,151
    Routes reached
    124 of 139
    Alert filters
    None
    Server errors
    0 unplanned
    API scan time
    77 min

    Findings at any level 0

    Findings by level

    • 0HighCould expose data
    • 0MediumWeakens a defence
    • 0LowMinor weakness
    • 0InformationalWorth knowing

    How we ran it

    How the scans were set up:

    • A test copy, not the live systemWe scanned the new version on a copy running on our own computer, with sample data only, before anyone used it. The 2 October scan below was of the live system.
    • Signed in three waysAs a clinic owner with two-step sign-in, as the same owner with a password only, and as a demo visitor who may only look. Each of these scans used all 52 attack rules.
    • No filtered resultsNo result was filtered out or marked as accepted. The planned “not available” answers from the password-reset email, which is switched off on the test copy, and one in each API scan from the Alpha application form, whose mail is also off on the test copy, were the only server errors.

    The scans

    Attack requests each scan sent, and how many findings it raised at any level. Bars are to scale.

    ScanRequestsShare of the largestFound
    Owner, two-step sign-inThe API, signed in as a clinic owner85,8450
    Owner, password onlyThe same owner, without two-step sign-in85,2190
    Demo visitorThe API, as a visitor who may only look80,8350
    Website and web appEvery page opened in a real browser, looking for script planted in a page2520

    Routes reached

    Each owner scan reached 124 of the API’s 139 routes. The ones they did not reach are 12 that only ReferralFinderX support uses, 2 less common actions, and the password-reset email (switched off on the test copy).

    A demo visitor may look around but never change anything. Signed in as one, the scanner tried to change data 28,082 times. Every attempt was refused, and none went through.

    In each API scan, a separate check also looked through every response, 254,750 in all, for a marker planted in another clinic’s records, and found none.

    What it found, and what it left out

    Nothing, at any level: no High, Medium, Low or Informational finding in any of the four scans. We got there by changing the code that earlier test scans pointed to, then scanning again, never by filtering results.

    The website and web app scan was not signed in.

  10. Text that looks like web-page code is refused when it is typed.

    ReferralFinderX now checks what people type before it is saved. Names, web addresses and phone numbers cannot contain the characters < or >. Longer text, such as notes and messages, cannot contain anything shaped like a piece of web-page code, such as <b>. The app already showed everything as plain text, so stored text could never run as code. Now it is not accepted in the first place.

    What you will notice

    Ordinary writing still saves, including “BP < 120” or “<2 weeks”. If something is refused, you see a plain sentence and your text stays in the box. Nothing already saved was changed.

  11. Looking never changes anything.

    Opening a page in ReferralFinderX only reads; it never changes what is stored, apart from the access records we keep on purpose. This is now one of the checks every release must pass: before anything ships, every read-only request the API offers is made as a clinic user and as ReferralFinderX support, and the release is held if any of them changes stored data. Downloading the activity log is now a deliberate action of its own, and it is still recorded in the log.

  12. Our website forms never put your details in a web address.

    The Alpha application and the contact form on our website send your details only in a secure request to ReferralFinderX, never as part of a web address, where they could end up in browser history or a server’s address log. If your browser has JavaScript turned off, the forms send nothing and tell you to email us instead.

  13. Less for a stranger to read in what we publish.

    The code your browser downloads to run the app and our website no longer carries our own explanatory notes or internal comments. They stay with our source code, where our team reads them. Our release checks now hold back any release that would publish them again.

  14. Demo cards that can only look.

    We added demo cards: a printed QR code that opens a short demo of ReferralFinderX with sample data. A demo visitor can look around but can never change anything. Our server enforces that on every request, not just the screen, and it also enforces the time limit. A card’s code is never sent in a web address our server sees, and we store it only in scrambled form, so even our own database cannot show the card’s code. Demo accounts are removed within two hours of their time running out, and a demo never opens a clinic’s real records.

    How we checked it

    Before release, we tried every kind of change as a demo visitor and confirmed each one was refused, and an independent review of the design and the code checked these rules. The attack scans above then repeated it at scale: signed in as a demo visitor, the scanner tried to change data 28,082 times and every attempt was refused.

  15. Every release is checked once it is live.

    After each release of the web app and this website, each page and every file it loads directly is compared with the one we built and reviewed. If any differs, the previous version is put back.

  16. Support needs a reason to look.

    When ReferralFinderX support needs to look at a clinic member’s personal items, such as their notes or saved searches, they must type a reason first. The clinic’s Masters see each of these looks, with its reason, on their Owner visits tab.

  17. Clinic separation, tested with real accounts.

    On a test copy, we tried every one of the 133 actions the API offered at the time, across 17 kinds of user in two clinics, one of them a visitor who is not signed in: 2,750 requests. None of them could see or change the other clinic’s information.

  18. Our software libraries are checked every week.

    Every change, and every Monday, the software libraries ReferralFinderX is built on are checked against public lists of known flaws, so a newly reported flaw reaches us even when nothing else changes.

  19. Signing out and password resets now end every session.

    We changed how the API checks sessions. After someone signs out of all devices, has two-step sign-in reset, or has their password reset by a clinic Master, the API refuses any session that started before that moment, including sessions that have since renewed themselves. We also updated the library that checks sign-in tokens to a release that fixes three published flaws.

    How we checked it

    Before it could ship, each change had to pass checks written to fail on the previous version and pass on this one. An independent review of the change found one problem before release: a Master resetting their own password could have locked themselves out. That reset now has to go through “Forgot password” instead.

  20. A signed-in attack scan of our API found no issues.

    We scanned the live ReferralFinderX API with ZAP, an open-source security scanner, while signed in. The scan sent 76,482 attack requests using all 52 of its active rules. No results were filtered out, and the report listed no findings at any level.

    Scan record

    Date
    2 Oct 2026
    Target
    Production API
    Tool
    ZAP 2.17
    Signed in
    As owner
    Attack rules
    52 of 52, finished in the one API scan
    Requests
    76,482
    Routes reached
    Not recorded in this scan
    Alert filters
    None
    Server errors
    0 unplanned
    API scan time
    36 min

    Findings at any level 0

    Findings by level

    • 0HighCould expose data
    • 0MediumWeakens a defence
    • 0LowMinor weakness
    • 0InformationalWorth knowing

    How we ran it

    How the scan was set up:

    • Live systemWe scanned the production API. The scanner worked inside a separate test clinic with no real accounts or patient information, which we deleted afterwards.
    • Signed inThe scanner used a clinic owner account with two-step sign-in, so it tested the parts of the API that require an account as well as the public ones.
    • No filtered resultsNo result was filtered out or marked as accepted. The Log4Shell check used a call-back server that we run ourselves.

    A sample of what it tried

    Eight of the 52 attack rules, with the number of requests each one sent. Bars are to scale.

    AttackRequestsShare of the largestFound
    SQL injectionTries to make the database run commands hidden in your input12,2260
    Command injectionTries to run commands on the server itself7,7810
    Path traversalTries to read files it should never reach7,5590
    Remote file inclusionTries to make the server load code from elsewhere5,0200
    Template injectionTries to make the server evaluate text as code3,5140
    Log4ShellThe 2021 logging flaw, tested with our own call-back server3,2630
    Open redirectTries to bounce a user to an outside site2,2590
    Cross-site scriptingTries to plant script that runs in someone else’s browser1,2380

    ZAP’s own names for these rules, in order: SqlInjection, CommandInjection, PathTraversal, RemoteFileInclude, Ssti, Log4Shell, ExternalRedirect, CrossSiteScripting.

    API performance during the scan

    While the scan ran, 95% of the API’s answers took 0.13 seconds or less on the server, it answered every health check, and it raised no server errors. A separate check looked through all 76,886 responses for a marker planted in another clinic’s records and found none. Testing clinic separation again, with real accounts on the current release, is part of what’s next.

    What it found, and what it left out

    Nothing, at any level: no High, Medium, Low or Informational finding.

    A short list of routes was left out on purpose:

    • routes that send real email;
    • routes that change user accounts;
    • routes that sign people out.

    The password reset was attacked on a safe copy on 13 October.

What’s next

A scan with no findings is only meaningful for the parts of the system it reached. These are the next steps in testing every part of ReferralFinderX, as every kind of user. Each one is added to the timeline above when it is complete.

  1. A scan for every other kind of userNext

    Full attack scans as advanced, basic and lite clinic users, and as a user whose team limits what they can see, on top of today’s owner and demo-visitor scans.

  2. Deeper attacks on one-time actionsNext

    Attack requests on every route in depth, including the actions that delete something or work only once, which today’s scans reached only a handful of times.

  3. Every kind of user, on the current releaseNext

    Re-run the real-account test on our test copy for the kinds of user not tested on the live system: demo visitors, and held, closed or disabled accounts.

  4. The web app, signed inNext

    Attack scans of the app as a signed-in user, not only the pages anyone can open.

  5. Sign-in, email settings and hosting, from the outsideNext

    Checks of our sign-in service, our protection against forged email, and our hosting setup.

  6. Independent penetration testPlanned

    An outside security firm tests ReferralFinderX by hand. We will publish its summary here.