← Back to all reports

Auth Bypass + IDOR on a Financial Advice Platform Exposes 132 Clients' PII to Any Free Account

Reported May 5, 2026
Severity Critical
Platform Web / API
Vulnerability Class Authentication Bypass + IDOR (CWE-287, CWE-639)
Target Type Financial Advice / Superannuation
Impact Mass financial PII disclosure for any web user

The Risk

Anyone could create a free account on the platform's website with any email address and instantly read every real client's financial fact-find: home addresses, mortgage balances, debts, income, retirement balances, super product names, even free-text notes from their adviser. The platform's own published policy said this kind of self-registered account should never be allowed, but the backend handed out a logged-in client session anyway. From there, two unprotected data endpoints exposed 615 fact-find records covering 132 real people, including names, dates of birth, mobile numbers, emails, super balances to the cent, and the contact details of their assigned adviser.

The Vulnerability

Three flaws chained into a single click. Any one of the three would have stopped the attack on its own.

Flaw 1, authentication bypass against the platform's own policy

The platform's public configuration endpoint declared that local-credential authentication and self-registration were disabled for the customer party type:

{"Authentication":{"UserType":{"Customer":{"LocalIDP":{
  "Enabled":"False","ResetPasswordRequest":"DISALLOWED","SelfRegister":"DISALLOWED"}}}}}

Despite this, GET /bff/login redirected to /auth/login with a fresh return URL, and POST /auth/v3/login accepted the credentials of any self-registered account, returning a fully usable browser session bound to the Client party type. The frontend correctly hid the password-login form. The backend never enforced the same policy. The web UI was the only thing keeping unauthorized users out, and the web UI was trivial to bypass.

Flaw 2, mass fact-find disclosure with no ownership filter

GET /profile-builder/v3/objects?limit=600 returned six hundred records across hundreds of collections with no ownership filter at all. Each record carried an objectType (such as InvestmentPropertyItem, DebtsItem, TaxDeductibleExpense, FreeTextNote) and a real data block. On a single test call, two hundred and three of the six hundred records contained filled financial data. Top object types: investment property items, additional income items, debts items, tax-deductible expenses, and free-text adviser notes.

Flaw 3, IDOR on the per-client journeys endpoint

GET /clients/{userId}/profile returned the target user's email, full name, date of birth, mobile, employment, super product, balances, investment options, risk profile, projected retirement balance, and assigned adviser, for any valid user ID, with no ownership check. A non-existent ID returned 404 Not Found, confirming that the server validated existence but not ownership. An adjacent documents endpoint correctly returned 403 for other clients, confirming the missing check on the journeys endpoint was an oversight, not by design.

The Attack

  1. Register a free account on the platform's public web sign-up page. No prior membership, no identity verification, no real-world relationship to the institution required.
  2. Hit GET /bff/login to capture correlation cookies and the password-login return URL.
  3. POST credentials to /auth/v3/login, complete the OIDC callback. The backend issued a session with idp: local and PartyType: Client.
  4. Call GET /profile-builder/v3/objects?limit=600. Response: six hundred fact-find records with property addresses, mortgages, debts, income, expenses, and free-text adviser notes belonging to a hundred and twenty-nine unique people.
  5. Pick any user ID from the response (each record carried revision.creator.principal.id) and call GET /clients/{userId}/profile. Response: full identity-grade profile and full superannuation profile for that client.

Verification was deliberately limited to three real victims, picked solely to demonstrate the depth of data exposed. Each victim's name, date of birth, mobile number, email, exact super balance, super products held, per-fund balances, risk profile, projected retirement balance, and assigned adviser were extracted from the live API in a single PoC run, with no estimation and no inference. Nothing was paginated, no document attachments were retrieved, and no further user IDs were enumerated even though the same session held the access rights to do so.

The Impact

  • Identity-grade PII for any user. Full name, date of birth, gender, email, mobile, employment status, planned retirement age, employer contribution rate.
  • Specific financial position for any user. Current super balance to the cent, preserved versus unrestricted split, exact product name, every investment option held with per-option balance, risk profile, projected retirement balance, lump-sum goal.
  • Fact-find dataset on top. Property addresses, mortgage balances, debt categories, rental income, tax-deductible expenses, free-text adviser notes for one hundred and thirty-two unique people in a single API call.
  • Adviser identity exposed. Every record showed the assigned adviser's email, enabling targeted phishing of advisers as a follow-on.
  • No barrier to entry. Free self-registration, no membership, no identity verification, no real customer relationship.
  • Regulatory exposure. Retirement-advice data plus identity PII for an Australian financial institution. Privacy Act 1988 (APP 11), APRA prudential standard CPS 234, and the Notifiable Data Breach scheme are likely engaged.
  • Downstream risk. Combined name, date of birth, phone, email, super fund, and balance are sufficient for SIM-swap, account takeover at the super fund, identity takeover at related institutions, and high-trust phishing of the user's adviser.

Remediation

Two minimum fixes. Either alone closes the chain.

  • Enforce the existing policy at the auth layer. The password-login endpoint must reject the customer party type when the platform's own policy says local-credential auth is disabled. Today the policy is enforced only on the frontend (the UI hides the form). The backend must check it.
  • Add ownership filtering on the fact-find and per-client journey endpoints. Both should scope results to the authenticated user's own records, the same way the documents endpoint already does.

Additional hardening:

  • Audit access logs over the exposure window for non-customer party-type sessions calling the two affected endpoints. Treat any hit as a confirmed data-access incident.
  • Notify the data subjects whose records were reachable and engage the regulator under the local data-breach scheme.
  • Add automated tests that exercise the policy contract from the backend, not just the frontend, so any future drift between the two surfaces is caught immediately.