Dan Gilbert prepared this portfolio sample from a security test of a new phone verification option on a member banking portal. This type of test, called a penetration test, looks for security weaknesses and confirms whether they can be used. Client names, account identifiers, values used to identify signed-in users, and phone numbers have been removed. The report uses example.com in place of actual website addresses.
Download the report with identifying details removed (PDF).
The phone verification option calls the number on file and reads a code. The member enters that code to continue into Balance Transfer, which moves a balance from another institution onto a line of credit. This extra login check is a form of multi-factor authentication, or MFA. We tested whether someone could reach the transfer page or move money without completing the required login and verification steps.
What we tested
Testing focused on the test versions of the banking portal and member center. One observation used a test account on the live system. We used a tool to inspect and resend messages between the browser and the application, then confirmed the results in a browser. We checked how verification codes were issued, used, and expired, along with browser cookies, security settings, third-party software, and connection encryption. When we found an incoming message from the phone service that fell outside the agreed scope, we met with the product team to review how it could be misused.
The most serious finding was a reusable login identifier placed in the web address after the member signed in. It began with the member's full Social Security number, and the application treated anyone with that link as authorized to use the account. Reusing it produced an unauthorized transfer. Opening it in a separate browser loaded the transfer page without a fresh login or verification code, and a tested link remained usable after logout. We observed the same behavior with both phone-call and text-message verification.
This exposed both funds and personal data. Web addresses can end up in browser history, support tickets, website analytics, and system logs. We rated the finding High because the link allowed a transfer without the normal login checks.
The application also failed to enforce its limit on failed verification attempts: a valid code could still succeed after that limit had been reached. Requests for verification calls were not limited tightly enough when sent rapidly or at the same time. Resending a saved request could still place a call after logout. While reviewing a system diagram, we found that the application accepted codes from messages claiming to come from Twilio, the phone service provider, without checking proof of their source. An attacker could imitate one of those messages and supply a code of their own, undermining the extra login check. This connection was outside the original scope, so we reviewed it with the product team before rating the issue's seriousness.
A lower-priority finding involved browser cookies used to track a login and prevent forged requests. In one test-system response during shared sign-in, those cookies lacked a setting that restricts them to encrypted connections. Other login cookies in the same responses had that setting, and normal pages told browsers to require secure connections. These protections limited the conditions for exposure, but protection was still inconsistent during login. Additional notes covered missing restrictions on which scripts and resources some login pages could load, an older encryption option on the test system (TLS 1.2 CBC), inconsistent security settings across responses, a third-party browser compatibility script, and a broken external resource on the transfer page. We kept those notes in an appendix to keep the fixes focused on the transfer issue.
What already worked
We also documented the protections that worked during testing so the team could preserve them while fixing the issues.
Codes expired after 15 minutes, and requesting a new code made the previous one unusable. Attempts to replace the phone number receiving the code were rejected. The verification call ended after three invalid selections. After around 1,100 automated attempts, a protective service in front of the application blocked access (HTTP 403) and required a CAPTCHA, a check intended to distinguish people from automated requests. Ordinary application responses told browsers to require secure connections.
How the report is meant to be used
Each rated finding explains how we collected the evidence, what the issue means for the business, why it received its rating, how to fix it, and how to check the fix. For the copied-link issue, a copied login identifier must no longer grant account access or allow a transfer. Changing the member or transfer details must cause the request to be rejected. Logging out must end access immediately, and web addresses and logs must no longer contain a Social Security number or reusable login secret. The application itself needs to enforce these rules, using login identifiers that reveal no personal information, keeping them in protected browser cookies, and checking that the signed-in member and approved transfer details still match the current login.
The phone verification fixes have equally specific checks. Once the failed-attempt limit is reached, even a valid code must be rejected, including when requests arrive at the same time or a new code has been requested. Requests made after logout must not place a call. Incoming messages from the phone service must not affect verification if they have been altered or lack proof of their source. A verified message must also match the verification request waiting for that member.
The retest notes ask for an owner and a date on each finding. They also ask the tester to record the software version, where and when the test ran, who ran it, evidence with identifying details removed, and the expected and actual results. Retesting covers successful phone verification, code expiration, replacement codes, and checks on the receiving phone number. A finding is only closed when the fix passes its checks and members can still use the feature as intended.
Where this sits in Lightning Kite's work
Lightning Kite designs and builds web applications, mobile apps, and the systems behind them. We also test how those applications work in practice. Automated security scans provide a starting point. This test required attempting the transfer, confirming the behavior in a browser, and defining how to check the fix.
For an engagement like this, we check who can access an account and approve a transfer, how verification attempts and calls are limited, whether messages from outside services can be trusted, how browser cookies are protected, and whether connections are encrypted. We prioritize findings by what an attacker could do. Other design and security improvements remain in the report, with the transfer that bypasses login taking priority. The report identifies who owns each fix, whether they manage the application, its connections to outside services, or the systems it runs on.
To have an existing workflow reviewed this way, start with software consulting. We agree on which paths to test and deliver a report your team can use to fix and retest the findings. You can decide separately whether to engage us for implementation.