Business ConfidentialSample report · fictitious client

SEE THE ACTUAL DELIVERABLE

Contoso Financial

Embedded-payments SaaS platform · Grey-box, senior-led, manual-first

Reference
CYB-2609
Test window
July 6, 2026 to July 17, 2026
Issued
July 22, 2026
Version
1.0

Executive Summary

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.

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

AssetDetail
app.contoso.exampleMerchant dashboard (single-page app)
api.contoso.exampleREST + GraphQL API, v2
pay.contoso.exampleHosted 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

  1. Scope & rules of engagementConfirmed targets, test accounts, allow-listing and safe-testing boundaries with Contoso before any traffic was sent.
  2. ReconnaissanceMapped the application and API surface (routes, GraphQL schema, JS bundles, auth flows, cloud fingerprints) to model the real attack surface.
  3. 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.
  4. Post-exploitation & impactDemonstrated business impact (cross-tenant access, admin control, cloud credential theft) without exfiltrating live data or disrupting service.
  5. ReportingDocumented each finding with evidence, CVSS 3.1, ATT&CK mapping, business impact and a concrete fix, plus this executive summary.
  6. RetestEvery fixed finding is re-tested at no additional cost, with written verification of closure.

Coverage

  • Authentication & session managementFindings
  • Authorization (object & function level)Findings
  • Injection (SQL, NoSQL, command)Findings
  • Cross-site scripting & output encodingFindings
  • Server-side request forgery & SSRF egressFindings
  • Business logic & payment flowsNo issues
  • Cryptography & transport securityNo issues
  • Cloud configuration (IAM, metadata, storage)Findings
  • Rate limiting & anti-automationFindings
  • Error handling & information disclosureFindings

Assessment team

  • 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

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.

SeverityCVSS rangeWhat it means
Critical9.0 to 10.0Exploitation is straightforward and typically yields full system or data compromise. Form a plan of action and remediate immediately.
High7.0 to 8.9Exploitation is harder or needs a foothold, but leads to elevated privileges, data loss or downtime. Remediate as soon as possible.
Medium4.0 to 6.9Exploitable with additional steps or specific conditions. Remediate after higher-priority issues are resolved.
Low0.1 to 3.9Limited direct impact, but reduces the overall attack surface once fixed. Address in the next maintenance window.
InfoN/ANo direct vulnerability. Observations, hardening opportunities and positive controls worth noting.

Findings Summary

Every finding at a glance, most severe first. Select any row to jump to its full write-up.

IDFindingSeverityCVSSRecommendation
CYB-01Insecure Direct Object Reference (IDOR) leading to account takeoverCritical9.6Enforce object-level authorization from the session on every read and write; use non-sequential identifiers as defence in depth.
CYB-02Server-Side Request Forgery in webhook validator reaching cloud credentialsHigh8.5Validate outbound URLs against an allow-list, block link-local ranges, and require IMDSv2 with a hop limit of 1.
CYB-03Pre-authentication SQL injection in catalog searchHigh7.5Use parameterised queries / prepared statements for every database call; never build SQL by string concatenation.
CYB-04JWT signature not verified (algorithm confusion) enabling admin impersonationCritical9.6Pin the accepted algorithm server-side and verify with the correct key; never derive the algorithm from the token.
CYB-05Mass assignment allows privilege escalation to administratorHigh8.1Bind only an explicit allow-list of user-editable fields; never map the raw request body onto the model.
CYB-06Stored cross-site scripting in the support consoleHigh7.6Context-encode all user data on output, render as text not HTML, and add a Content-Security-Policy.
CYB-07No rate limiting on authentication and MFA endpointsMedium5.3Apply per-account and per-IP rate limiting, progressive backoff, and a hard cap on MFA verification attempts.
CYB-08Sensitive information disclosure in verbose error responsesMedium4.3Return generic error responses to clients; log detail server-side only and disable debug mode in production.
CYB-09Missing session-cookie flags and security response headersLow3.1Set HttpOnly, Secure, and SameSite on session cookies and add the standard security response headers.
CYB-10Username enumeration via authentication response timingLow3.7Make the authentication path constant-time regardless of whether the account exists.
CYB-11Deprecated API version still reachableInfoN/ADecommission or authenticate-and-monitor the legacy API; document a version-retirement policy.

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.

  1. 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.

    CYB-11
  2. Initial AccessT1190 · Exploit Public-Facing Application

    With no credentials, exploited SQL injection in the public catalog search to read the customer datastore, recovering account records and password hashes.

    CYB-03
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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

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
  1. Authenticate as a standard merchant and note your own account identifier (for example 48213).
  2. Request the next identifier, GET /api/v2/accounts/48214, with your own bearer token.
  3. Observe another tenant’s record is returned (HTTP 200) despite no ownership relationship.
  4. Issue PATCH /api/v2/accounts/48214 with {"email":"attacker@evil.example"} and observe HTTP 204. The change is accepted.
Evidence · 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":"cfo@othertenant.example","payout":"acct_1M9x••"}# no ownership check. Now flip the email on file to one we control:PATCH /api/v2/accounts/48214 HTTP/2   {"email":"attacker@evil.example"}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
  1. 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.
  2. 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.
  3. 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.

Showing finding 1 of 11. Unlock the rest below.