User IDs are sequential
Your profile URL is /u/1042. So is everybody else's, in order.
For whoever has to approve this
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
Not a checklist we tick — the areas an attacker works through in order, and the areas your report is organised by.
Login, password reset, MFA, account recovery
Role boundaries, tenant isolation, admin routes
Tokens, cookies, fixation, expiry, logout
SQL, NoSQL, command, template, XSS, SSRF
Uploads, path traversal, deserialisation
REST and GraphQL, endpoint by endpoint, role by role
Storage, pinning, hardcoded secrets, tampering
Buckets, IAM, metadata endpoints, exposed services
Pricing, quotas, refunds, invites, workflows
TLS, headers, patch level, open ports, DNS
How findings are rated
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.
Two worked findings
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.
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": [ … ] }
An illustrative finding, not a client's. The shape, the evidence and the fix advice are what every entry in your report looks like.
# 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
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
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.
Your profile URL is /u/1042. So is everybody else's, in order.
A registered address gets “check your inbox”, an unregistered one gets “no such user”.
A token issued for one browser is accepted in another.
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
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
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.
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.
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.
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.
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.
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
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.
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
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.
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.
Start and end date and, if you want them, hours of the day. Outside the window nothing runs.
A named person and a direct contact on each side. Either of yours can stop the test instantly, for any reason, without explaining.
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.
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.
We do not phish your staff, call your helpdesk or walk into your office unless that is separately scoped and authorised.
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.
Anything Critical is reported the hour it is confirmed, out of band, not saved up for the report.
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.
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
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.
Delivery
The report itself, signed, with the evidence appendix.
Every finding as a row — id, title, severity, CVSS, component, status — for a spreadsheet or a risk register.
The same data structured, for your own tooling.
The standard static-analysis format, so findings load straight into GitHub code scanning, GitLab or Defect Dojo alongside everything else you already track.
One ticket per finding, with severity, reproduction steps and the fix, imported for you if you want it.
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
In plain words
Next step
One reply from the engineer who would run the test — the engagement that fits, the fixed price, and the earliest window.