Contoso Financial is a fictitious company created solely for this sample report. It is not a real organisation, and any resemblance to a real company, system, or individual is coincidental. The findings below demonstrate the format, depth, and technical rigour of a genuine Cybros engagement.
Between July 6 and July 17, 2026, Contoso Financial engaged Cybros Security Solutions to test its merchant platform: the customer-facing dashboard, the v2 REST and GraphQL API behind it, the hosted checkout, and a configuration review of the supporting AWS workloads. Testing was grey-box and manual-first. Every finding in this report was reproduced by hand, not reported from a scanner.
We identified eleven findings: two Critical, four High, two Medium, two Low and one Informational. The two Critical findings share one root cause. Authorization is trusted from client-supplied input instead of being enforced server-side against the authenticated session. With nothing more than a standard merchant account, we read and modified other merchants’ records (CYB-01) and forged an administrator identity the API accepted as valid (CYB-04). Either issue on its own lets one customer take over another customer’s account or reach platform administration.
The remaining findings widen that exposure rather than sitting apart from it. A server-side request forgery flaw in the webhook validator (CYB-02) reached the cloud instance metadata service and returned live IAM credentials. A pre-authentication SQL injection in catalog search (CYB-03) exposed the customer datastore. A mass-assignment flaw (CYB-05) let an ordinary user grant themselves the admin role. Chained, these give a single unauthenticated attacker a credible route from the public internet to both the customer database and the cloud account, reproduced step by step in Path to Compromise.
None of this is unusual for a fast-moving platform, and none of it needs a rewrite. Every Critical and High finding is a bounded, well-understood fix: enforce object- and function-level authorization from the session, verify token signatures with a pinned algorithm, and treat all outbound URLs and SQL inputs as hostile. Contoso also does several things well (see Strengths). With the roadmap in this report the exploitable risk closes inside one to two sprints, and we verify it for free at retest.
What Contoso does well
TLS 1.3 with HSTS preloading was enforced across every in-scope host. No transport downgrade was possible.
The hosted checkout tokenises card data at the processor, so no PAN reached Contoso’s own systems in scope.
A WAF blocked naive, automated payloads and forced manual technique. It slowed testing; it did not stop it.
The security team detected and queried our scanning activity inside the testing window: a working detection capability.
Where the risk concentrates
Authorization is inconsistently enforced. Object- and function-level checks are missing on multiple API endpoints.
Trust is placed in client-controlled input: object identifiers, tenant scope, request bodies, and even a token’s own signing algorithm.
Outbound requests from the API are unrestricted, which exposes internal cloud metadata via SSRF.
Defence in depth is thin. Verbose errors, missing cookie flags and absent security headers each widen the blast radius of the issues above.
02
Engagement & Scope
Contoso Financial engaged Cybros to assess the security of its merchant platform between July 6, 2026 and July 17, 2026. Testing followed PTES, OWASP WSTG v4.2, OWASP API Security Top 10 (2023), NIST SP 800-115 and MITRE ATT&CK. Every finding was confirmed manually.
In scope
Asset
Detail
app.contoso.example
Merchant dashboard (single-page app)
api.contoso.example
REST + GraphQL API, v2
pay.contoso.example
Hosted checkout & payment widget
AWS account 4021-••••
Configuration review of the in-scope workloads
Allowances
Two seeded merchant accounts (one standard, one admin) on the staging tenant
Test API keys and a sandbox payment processor
Source IP allow-listed through the WAF to test the application, not the WAF
Exclusions
Denial-of-service and volumetric / stress testing
Phishing and social engineering against Contoso staff
Physical security and on-site testing
Third-party PCI card networks and acquiring banks
How we tested
01
Scope & rules of engagementConfirmed targets, test accounts, allow-listing and safe-testing boundaries with Contoso before any traffic was sent.
02
ReconnaissanceMapped the application and API surface (routes, GraphQL schema, JS bundles, auth flows, cloud fingerprints) to model the real attack surface.
03
Manual testing & exploitationHands-on testing against OWASP WSTG and the API Top 10. Every candidate issue was proven by safe exploitation, then chained the way a real attacker would.
04
Post-exploitation & impactDemonstrated business impact (cross-tenant access, admin control, cloud credential theft) without exfiltrating live data or disrupting service.
05
ReportingDocumented each finding with evidence, CVSS 3.1, ATT&CK mapping, business impact and a concrete fix, plus this executive summary.
06
RetestEvery fixed finding is re-tested at no additional cost, with written verification of closure.
A. OkonkwoEngagement lead · web & API exploitationOSCP · OSWE
S. VossAPI & cloud configuration testingOSCP · CRTP
M. HaddadTechnical review & CVSS quality assuranceeWPTX · CISSP
Tooling
Burp Suite Professional · ffuf · sqlmap · nuclei · jwt_tool · Amass / httpx · aws cli
03
Severity Ratings
Each finding is scored with CVSS 3.1. The base score sets the severity band below, and risk is described in plain language as likelihood × impact so non-specialists can prioritise with confidence.
Severity
CVSS range
What it means
Critical
9.0 to 10.0
Exploitation is straightforward and typically yields full system or data compromise. Form a plan of action and remediate immediately.
High
7.0 to 8.9
Exploitation is harder or needs a foothold, but leads to elevated privileges, data loss or downtime. Remediate as soon as possible.
Medium
4.0 to 6.9
Exploitable with additional steps or specific conditions. Remediate after higher-priority issues are resolved.
Low
0.1 to 3.9
Limited direct impact, but reduces the overall attack surface once fixed. Address in the next maintenance window.
Info
N/A
No direct vulnerability. Observations, hardening opportunities and positive controls worth noting.
04
Findings Summary
Every finding at a glance, most severe first. Select any row to jump to its full write-up.
ID
Finding
Severity
CVSS
Recommendation
CYB-01
Insecure Direct Object Reference (IDOR) leading to account takeover
Critical
9.6
Enforce object-level authorization from the session on every read and write; use non-sequential identifiers as defence in depth.
CYB-02
Server-Side Request Forgery in webhook validator reaching cloud credentials
High
8.5
Validate outbound URLs against an allow-list, block link-local ranges, and require IMDSv2 with a hop limit of 1.
CYB-03
Pre-authentication SQL injection in catalog search
High
7.5
Use parameterised queries / prepared statements for every database call; never build SQL by string concatenation.
CYB-04
JWT signature not verified (algorithm confusion) enabling admin impersonation
Critical
9.6
Pin the accepted algorithm server-side and verify with the correct key; never derive the algorithm from the token.
CYB-05
Mass assignment allows privilege escalation to administrator
High
8.1
Bind only an explicit allow-list of user-editable fields; never map the raw request body onto the model.
CYB-06
Stored cross-site scripting in the support console
High
7.6
Context-encode all user data on output, render as text not HTML, and add a Content-Security-Policy.
CYB-07
No rate limiting on authentication and MFA endpoints
Medium
5.3
Apply per-account and per-IP rate limiting, progressive backoff, and a hard cap on MFA verification attempts.
CYB-08
Sensitive information disclosure in verbose error responses
Medium
4.3
Return generic error responses to clients; log detail server-side only and disable debug mode in production.
CYB-09
Missing session-cookie flags and security response headers
Low
3.1
Set HttpOnly, Secure, and SameSite on session cookies and add the standard security response headers.
CYB-10
Username enumeration via authentication response timing
Low
3.7
Make the authentication path constant-time regardless of whether the account exists.
CYB-11
Deprecated API version still reachable
Info
N/A
Decommission or authenticate-and-monitor the legacy API; document a version-retirement policy.
05
Path to Compromise
The findings are not isolated. Chained, they take a single attacker from the public internet to both the customer database and the cloud account. Below is the exact route we walked, mapped to MITRE ATT&CK.
01
ReconnaissanceT1595 · Active Scanning
Mapped the public application and API surface (routes, the GraphQL schema, JS bundles and the JWKS endpoint) to model where authorization and trust decisions are made.
With no credentials, exploited SQL injection in the public catalog search to read the customer datastore, recovering account records and password hashes.
CYB-03
03
Privilege EscalationT1068 · Exploitation for Privilege Escalation
Registered a standard merchant account and promoted it to administrator by adding a role field to a routine profile update.
CYB-05
04
Credential AccessT1606 · Forge Web Credentials
Independently forged a valid administrator token by re-signing a JWT with the exposed public key, confirming a second, distinct route to platform administration.
CYB-04
05
CollectionT1078 · Valid Accounts
From an ordinary account, enumerated and took over other merchants’ accounts by incrementing object identifiers and changing the email on file.
CYB-01
06
Credential AccessT1552.005 · Cloud Instance Metadata API
Abused the webhook validator to reach the cloud metadata service and retrieve live IAM credentials, pivoting from the application into the AWS account.
CYB-02
07
ImpactT1078 · Valid Accounts
Held two independent routes to full administrative control of the platform plus live cloud credentials, enough to reach every tenant’s data and the supporting infrastructure.
CYB-04
06
Technical Findings
Each finding: what it is, proof it is real, steps to reproduce, business impact, and a concrete fix.
CYB-01CriticalCVSS 9.6
Insecure Direct Object Reference (IDOR) leading to account takeover
AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N
Classification
CWE-639
Category
API1:2023 · Broken Object Level Authorization
ATT&CK
T1078 · Valid Accounts
Status
Open
Affectedapi.contoso.example · account service
GET /api/v2/accounts/{id}
PATCH /api/v2/accounts/{id}
Description
The account API addresses records by a sequential integer identifier. When a request asks for an identifier the caller does not own, the API returns and updates the record anyway. Ownership is never checked server-side. The authenticated session is used to let the request in, but not to decide which objects it may touch.
From a standard merchant account we incremented the identifier, read another tenant’s account record, then issued a PATCH that changed the email address on file. Because a password reset is delivered to the email on file, changing it is equivalent to taking the account over outright.
Likelihood · High
The identifier is a small integer and the flaw is found simply by incrementing it. No special tooling or timing is required: a browser and a valid account are enough.
Impact · Very High
Any authenticated merchant can read and modify every other merchant’s account, including seizing it via an email change. This is a direct cross-tenant confidentiality and integrity breach.
Steps to reproduce
Authenticate as a standard merchant and note your own account identifier (for example 48213).
Request the next identifier, GET /api/v2/accounts/48214, with your own bearer token.
Observe another tenant’s record is returned (HTTP 200) despite no ownership relationship.
Issue PATCH /api/v2/accounts/48214 with {"email":"[email protected]"} and observe HTTP 204. The change is accepted.
Evidence · Burp Suite Professional · Repeater
Burp Suite Professional · Repeater
# 48213 is our own seeded account. Increment the identifier by one:GET /api/v2/accounts/48214 HTTP/2Host: api.contoso.exampleAuthorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjQ4MjEz...HTTP/2 200 OK · x-request-id: 7f3c1a9e · 238 bytes{"id":48214,"tenant":"contoso-mer","email":"[email protected]","payout":"acct_1M9x••"}# no ownership check. Now flip the email on file to one we control:PATCH /api/v2/accounts/48214 HTTP/2 {"email":"[email protected]"}HTTP/2 204 No Content ← write accepted; a password reset now lands in our mailbox
Captured in Burp Suite while authenticated as merchant 48213. A read and then a write both succeed against an account we do not own.
Business impact
A single paying customer could enumerate and take over any other customer on the platform, read their settlement details and change their payout email. For a payments provider this is both a direct financial-fraud vector and a reportable data breach.
Remediation
Enforce object-level authorization on every request: confirm the authenticated subject owns (or has an explicit grant to) the object before it is read or mutated. This check belongs in shared middleware, not per-handler.
Switch account identifiers to non-sequential, non-guessable values (UUIDv4 or ULID) so enumeration is not trivial. Treat this as defence in depth, not the fix.
Add an automated authorization test per endpoint to CI: a second, unrelated identity must receive 403 for objects it does not own, and the build must fail if it receives 200.