FD Solutions Security testing

For whoever has to approve this

How we test, what we run,
and what we are allowed to do.

Published before you enquire rather than after you sign. If any of it does not match what you need, say so and we will change the scope, not the wording.

What gets tested

Ten places things go wrong.

Not a checklist we tick — the areas an attacker works through in order, and the areas your report is organised by.

Authentication

Login, password reset, MFA, account recovery

Access control

Role boundaries, tenant isolation, admin routes

Sessions

Tokens, cookies, fixation, expiry, logout

Injection

SQL, NoSQL, command, template, XSS, SSRF

File handling

Uploads, path traversal, deserialisation

APIs

REST and GraphQL, endpoint by endpoint, role by role

Mobile

Storage, pinning, hardcoded secrets, tampering

Cloud

Buckets, IAM, metadata endpoints, exposed services

Business logic

Pricing, quotas, refunds, invites, workflows

Infrastructure

TLS, headers, patch level, open ports, DNS

How findings are rated

CVSS, then business context.

A Medium on a marketing page and a Medium on a payments endpoint are not the same problem. The score sorts them; the context decides what you do on Monday, and your report says both.

Critical 9.0 – 10.0 Someone can take over accounts, read the database or run code on your server. No skill barrier worth the name. You hear within the hour we confirm it
High 7.0 – 8.9 Serious exposure of data or function, but needs a condition to be met — a valid account, a specific role, a user to click. Same working day
Medium 4.0 – 6.9 Real, exploitable, and usually the link that turns two small problems into one large one. In the report
Low 0.1 – 3.9 Limited impact on its own. Worth fixing because attackers chain these, and because they are usually cheap. In the report
Informational 0.0 Not a vulnerability. Hardening, hygiene and things that will become vulnerabilities as the product grows. In the report

Two worked findings

What a finding looks like when we hand it over.

The first is a textbook authorisation flaw. The second is the kind no scanner can report, because there is nothing malformed about any of the requests.

High FDS-2026-014 GET /api/v2/invoices/{id}
GET /api/v2/invoices/40817 HTTP/2
Host: app.example.com
Authorization: Bearer eyJhbGciOi… [account 40, role: customer]
HTTP/2 200 OK
Content-Type: application/json
{ "invoice_id": 40817, "account_id": 22,
  "billing_email": "██████@████.com",
  "card_last4": "████", "amount": 4200,
  "line_items": [ … ] }

Any authenticated user can read any other user's invoices

SeverityCVSS 8.1 · CVSS:4.0 / AV:N / AC:L / PR:L / UI:N
ClassCWE-639 — Authorisation bypass through user-controlled key
What the evidence showsAccount 40 requested an invoice belonging to account 22 and the server returned it. Incrementing the id walks the whole table.
Business impactEvery invoice in the system is readable by any registered user, including billing addresses and partial card data. One script, one afternoon, and it is a notifiable data breach.
How to fix itScope the query to the caller's account rather than trusting the id in the path: filter on account_id from the session, and return 404 rather than 403 so the endpoint does not confirm which ids exist.

An illustrative finding, not a client's. The shape, the evidence and the fix advice are what every entry in your report looks like.

Critical FDS-2026-031 POST /api/v2/orders/{id}/refund
# 20 identical requests, sent in parallel, one order
POST /api/v2/orders/88214/refund HTTP/2
Content-Type: application/json
{ "amount": 4200, "reason": "duplicate" }
HTTP/2 200 OK    ×7      refund accepted
HTTP/2 409       ×13     already refunded
Order total charged:   $42.00
Total refunded:       $294.00

Refunds can be issued against an order twice by racing the request

SeverityCVSS 9.1 · Business logic — no CVE, no signature, no scanner rule
ClassCWE-362 — Race condition in a check-then-act sequence
What the evidence showsThe handler reads the order status, decides no refund has been issued, then writes one. Between the read and the write, six other requests made the same decision.
Business impactAny customer who can refund their own order can extract roughly seven times its value, repeatedly, using a tool that ships with every browser's developer console. Nothing in the logs looks like an attack — every request is a valid, authenticated, correctly-formed refund.
How to fix itTake a row-level lock on the order, or add a unique constraint on (order_id, refund) and let the database refuse the second write. Moving the check inside the same transaction as the write is the whole fix; an application-level flag is not.

Also illustrative. No scanner reports this one — there is no signature to match, no version to compare and nothing malformed about any of the twenty requests. Finding it means understanding what your product is supposed to refuse to do.

Why a person, not a scanner

Three findings a scanner calls minor — and one that ends your week.

Each of these three is real, each scores low enough to be deprioritised, and no tool joins them up — because joining them up means understanding what your product is for.

Low

User IDs are sequential

Your profile URL is /u/1042. So is everybody else's, in order.

Low

Password reset reveals whether an account exists

A registered address gets “check your inbox”, an unregistered one gets “no such user”.

Medium

Reset token is not bound to a session

A token issued for one browser is accepted in another.

Critical

Account takeover, at scale

Enumerate the users, confirm which addresses are real, request resets and use the tokens from anywhere. Individually these score 3.1, 3.7 and 5.3 and get closed as “minor”. Chained, they are your whole user table — and only a person testing the flows joins them up.

Standards

Named in your report, by section.

OWASP WSTG

Web Security Testing Guide — the test cases for web applications

OWASP ASVS

Application Security Verification Standard — the level we verify against

OWASP API Top 10

The failure modes specific to APIs, especially authorisation

OWASP MASVS

Mobile Application Security Verification Standard, for iOS and Android

PTES

Penetration Testing Execution Standard — how the engagement is structured

NIST SP 800-115

The technical guide auditors expect a methodology to reference

Nothing happens without written authorisation

A signed scope and authorisation letter naming the exact systems, the testing window and the people who may stop the test. Your host may need a copy; we write that for you. No packet is sent before it is signed.

Non-destructive by default

We prove a vulnerability exists; we do not exploit it further than proof requires. No data is deleted, no records are altered, no denial-of-service testing unless you ask for it in writing.

Your data stays yours

Where a finding exposes real records we capture the minimum needed as evidence, redact it, and destroy the working copies when the engagement closes. NDA signed before scoping, as standard.

Every finding is verified by a person

Automation finds candidates. A human confirms each one before it reaches your report. You should never spend a sprint chasing a false positive that we could have ruled out in ten minutes.

The report is yours, in full

No watermarked teaser, no upsell version, no portal you lose access to when the subscription lapses. You get the PDF, the raw evidence and the machine-readable export, and you may share them with anyone.

One named engineer, start to finish

The person who scopes it runs it, writes it, and answers your engineers' questions on it. You are not handed to a queue between stages.

Tooling

What we actually run.

Automation does the sweeping. A person does the judging. Here is what that means in practice, because a vendor who will not tell you what they run is usually running one free scanner.

Web and API
Burp Suite Professional with custom extensions, ffuf and feroxbuster for content discovery, nuclei for known issues, sqlmap where injection is indicated, Postman and custom Python for authorisation matrices
Mobile
MobSF for the first pass, jadx and apktool on Android, Frida and objection for runtime work, Ghidra where a binary needs reading
Code and dependencies
Semgrep and CodeQL where source access is granted, Trivy and Grype for dependencies and container images, gitleaks and trufflehog for secrets in history
Infrastructure and recon
nmap, testssl.sh, amass and subfinder, ScoutSuite and Prowler for cloud posture, plus the DNS and certificate transparency records
Written by hand
The authorisation-matrix walker, the multi-role session differ, and the business-logic harnesses — because no off-the-shelf tool knows what your product is supposed to refuse to do

No tool output reaches your report unread. Automation produces candidates; a person confirms, discards or escalates every one of them, and the discarded ones are listed too, so you can see what was ruled out and why.

Rules of engagement

What you are agreeing to let us do.

Every engagement runs under a written authorisation letter. Here is what is in it, before you enquire rather than after — you should never have to guess what you are agreeing to.

  1. Named targets only

    Exact hostnames, IP ranges, app bundle identifiers and API base URLs, listed. Anything not on the list is out of scope even if it is obviously yours, and we come back and ask rather than assume.

  2. A window you choose

    Start and end date and, if you want them, hours of the day. Outside the window nothing runs.

  3. Two stop contacts

    A named person and a direct contact on each side. Either of yours can stop the test instantly, for any reason, without explaining.

  4. No denial of service

    No load testing, no resource exhaustion, no attack whose purpose is to make the system unavailable — unless you ask for it in writing as a separate exercise.

  5. No destructive actions

    Nothing deleted, nothing modified beyond what proving a finding requires, and anything we do create is recorded so you can clean it up. Test data is marked as ours.

  6. No social engineering by default

    We do not phish your staff, call your helpdesk or walk into your office unless that is separately scoped and authorised.

  7. Third parties handled first

    If you are on shared hosting or a managed platform, the provider's notice or permission is obtained before we start. We draft that message; you send it.

  8. Critical findings are not held back

    Anything Critical is reported the hour it is confirmed, out of band, not saved up for the report.

  9. Immediate stop conditions

    We stop and contact you immediately if we reach production customer data we did not expect, if we find evidence of a prior compromise, or if anything appears to be degrading.

  10. Your report is yours

    You own it. We take no publicity rights, name you nowhere without written permission, and the NDA runs both ways.

Want the full authorisation letter template before you enquire? Ask and we will send it — no obligation, and no form beyond your email address.

Your data

Specifics, with numbers on them.

During a test we necessarily hold evidence about your systems and sometimes about your users. "We take security seriously" is not an answer, so here are the specifics — the same ones we would want from a vendor.

Where evidence is stored
Full-disk-encrypted machines under our control, in an encrypted container per engagement. Never a personal device, never a shared drive, never an AI service.
How much we capture
The minimum that proves the finding. Where real records are exposed we capture one, redact identifying fields in the report, and do not download the rest — proving a table is readable does not require reading the table.
How long we keep it
Working evidence is destroyed 30 days after the report is accepted. The report itself and its evidence appendix are kept for 12 months so we can retest and answer auditor questions, then deleted.
Who can see it
The engineer running your engagement. No subcontractors without your written agreement naming them, and no third-party portal holding your findings.
Credentials you give us
Test accounts only, created for the engagement, in a password manager entry we delete at the end. We will ask you to rotate them on the day the report is delivered, and the report says so in writing.
If we find your data already leaked
You hear the same day, before the report, with what we found and where — because a credential already published elsewhere is not a finding that can wait for a document.
If the breach is ours
You are told within 24 hours of us knowing, in writing, with what was exposed and when — before the investigation is finished rather than after it. The obligation is in the contract, and it runs even if the engagement ended a year ago.
What never touches it
No hosted AI or assistant, no shared drive, no third-party findings portal, no subcontractor's device. Your architecture is not training data and your evidence is not somebody else's SaaS backlog.
Deletion on request
Ask, in writing, at any time, and everything except the records we are legally required to keep is destroyed within 5 working days, with written confirmation.

Delivery

Formats your tooling already reads.

PDF

The report itself, signed, with the evidence appendix.

CSV

Every finding as a row — id, title, severity, CVSS, component, status — for a spreadsheet or a risk register.

JSON

The same data structured, for your own tooling.

SARIF

The standard static-analysis format, so findings load straight into GitHub code scanning, GitLab or Defect Dojo alongside everything else you already track.

Jira / Linear

One ticket per finding, with severity, reproduction steps and the fix, imported for you if you want it.

Webhook

On request: a POST to your endpoint when a finding is raised or its status changes, so a Critical reaches your on-call channel rather than an inbox.

Everything else

Questions, answered properly.

In plain words

Every term on these pages, without the jargon.

Penetration test (pentest)
A person deliberately trying to break into your system, with your written permission, so you find out before someone does it without.
Vulnerability
A specific mistake an attacker can use — a missing check, an old library, a password rule that lets 'password1' through.
OWASP
A non-profit that publishes the standard lists of what goes wrong in web and mobile applications. Auditors expect a tester to work from them.
OWASP Top 10
The ten most common categories of web application flaw. If a vendor cannot tell you how they covered these, they did not test properly.
CVSS
The industry's 0–10 severity score. Useful for sorting, useless on its own — a 7.5 on your billing system and a 7.5 on your blog are not the same problem.
Critical / High / Medium / Low
How urgent a finding is. Critical means someone can get in today with no special skill. Low means it matters mainly as a step in a chain.
Access control / IDOR
Whether the software checks that you are allowed to see the thing you asked for. IDOR is when changing a number in the address bar shows you somebody else's data.
Authentication
Proving who you are: login, password reset, two-factor, 'forgot my password'. Historically where the worst failures live.
API
The part of your product other software talks to — your mobile app, a partner's system, your own front end. It is often less protected than the website, and attacked more.
Retest
Testing again after you fix things, to confirm the fix actually worked. Roughly a third of 'fixed' findings are not fixed on the first attempt.
Scope
The written list of exactly what we are allowed to test, when, and how far. Nothing outside it is touched.
Remediation
Fixing what was found. Our report tells you what to change and in what order; you or we can do the work.

Next step

Send us a URL. Get a price today.

One reply from the engineer who would run the test — the engagement that fits, the fixed price, and the earliest window.

WhatsApp Get a price