01 / EXECUTIVE CONCLUSION
Release decision and business exposure
HIGH RISK
RECOMMENDATION
Do not release the tested version until HC-01 and HC-02 are fixed and independently
retested.
Authentication worked as intended, but authorization was not enforced consistently
after login. A standard user could promote their own account to platform administrator
and access another tenant's invoice by changing data already controlled in the browser.
Both attack paths were reproduced with ordinary test accounts and required no malware,
social engineering or infrastructure access.
If exploited in a real environment, the issues could expose customer and billing data,
permit privileged administrative actions and undermine tenant isolation. Likely business
consequences include contractual breach, incident-response costs, regulatory review and
loss of customer trust.
No unauthenticated server compromise, remote code execution or denial-of-service issue
was confirmed within the agreed scope. This does not reduce the urgency of the two high
findings: together they form a credible path from a low-privilege account to cross-tenant
data access and administrative control.
0Critical
2High
1Medium
1Low
1Informational
02 / SCOPE & METHOD
What was tested
| In-scope assets | app.demo.example and api.demo.example/v1 |
| Test identities | Standard User, Billing Manager and Platform Administrator |
| Tenant boundary | Fictional tenants Alpha Labs and Beta Works |
| Testing mode | Authenticated grey-box testing with API documentation |
| Excluded | Denial of service, social engineering, source review and third-party providers |
Testing combined manual exploration with supporting tools. Coverage focused on
authentication, authorization, tenant isolation, session handling, input processing,
sensitive-data exposure and critical business workflows. Guidance from OWASP WSTG,
OWASP ASVS and the OWASP API Security Top 10 informed test cases; it was not treated as
a substitute for application-specific attack-path analysis.
03 / RISK RATING
Technical severity and business priority
CVSS 3.1 records the technical characteristics of a vulnerability. Business priority is
then adjusted using the sensitivity of affected data, number of exposed tenants,
attacker prerequisites, detectability and operational consequences. CVSS is a severity
score, not a complete statement of business risk.
Critical9.0–10.0
High7.0–8.9
Medium4.0–6.9
Low0.1–3.9
InfoNo CVSS score
04 / FINDINGS SUMMARY
Prioritized results
| ID | Finding | CVSS 3.1 | Status |
| HC-02 | Role escalation through mass assignment | 8.8 High | Open |
| HC-01 | Cross-tenant invoice access (BOLA) | 7.1 High | Open |
| HC-03 | Sessions remain valid after password change | 5.4 Medium | Open |
| HC-04 | Verbose API errors expose internal schema | 3.7 Low | Open |
| HC-05 | Content Security Policy not defined | Informational | Open |
05 / DETAILED FINDING
HC-02 / Role escalation through mass assignment
8.8HIGH
- Affected endpoint
- PATCH /api/v1/users/{userId}
- Required access
- Any authenticated Standard User
- Classification
- OWASP API3:2023 / CWE-915
- CVSS 3.1 vector
- AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
What was found
The profile-update endpoint accepted the privileged role property from a
Standard User. The server wrote that value directly to the user record and issued an
updated session containing the administrator role. The user interface did not expose
this field, but hiding it in the browser did not provide server-side protection.
Attack path reproduced
- The assessor signed in with the Standard User account
[email protected].
- A legitimate profile-name update was intercepted in the browser.
- The assessor added
"role":"platform_admin" to the JSON body.
- The API returned
200 OK and stored the new role without an authorization check.
- The same account then opened the administrator export endpoint and received tenant data.
REQUEST / PRIVILEGE CHANGE
PATCH /api/v1/users/usr_demo_1048 HTTP/1.1
Host: api.demo.example
Authorization: Bearer [redacted]
Content-Type: application/json
{
"displayName": "A. Tester",
"role": "platform_admin"
}
RESPONSE / SERVER ACCEPTED ROLE
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "usr_demo_1048",
"displayName": "A. Tester",
"role": "platform_admin"
}
VALIDATION / ADMINISTRATOR ACTION
GET /api/v1/admin/customers/export HTTP/1.1
Authorization: Bearer [same user session]
HTTP/1.1 200 OK
Content-Type: text/csv
[response body redacted]
Business impact
Any compromised or malicious customer account could become a platform administrator.
In the tested version this exposed customer exports and administrative functions,
affecting confidentiality, integrity and availability across tenant boundaries.
Root cause
A general-purpose user model was bound directly to client-controlled JSON. The endpoint
did not use an allowlist of editable profile fields, and administrator routes trusted the
stored role without recording how it had been assigned.
Recommended fix
- Use a dedicated self-service profile DTO that does not contain role or permission fields.
- Allow role changes only through a separate administrative operation with explicit authorization.
- Enforce authorization centrally on every administrator route and deny access by default.
- Audit role changes with actor, target, previous value, new value and request identifier.
- Invalidate existing sessions when privileges change and add negative authorization tests.
Retest criteria
Repeating the modified profile request must ignore or reject role. A Standard
User must receive 403 Forbidden from every administrator endpoint. Legitimate
administrator role changes must still work through the approved workflow and create an
audit event. Equivalent fields such as permissions, tenantId and
isAdmin must also be checked.
06 / DETAILED FINDING
HC-01 / Cross-tenant invoice access
7.1HIGH
- Affected endpoint
- GET /api/v1/invoices/{invoiceId}
- Required access
- Authenticated user in any tenant
- Classification
- OWASP API1:2023 BOLA / CWE-639
- CVSS 3.1 vector
- AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N
What was found
Invoice records were retrieved by their identifier without checking that the invoice
belonged to the caller's tenant. While authenticated as Tenant Alpha, changing one
identifier returned an invoice owned by Tenant Beta, including customer name, billing
address, line items and payment status.
AUTHORIZED BASELINE / TENANT ALPHA
GET /api/v1/invoices/inv_demo_1048
Authorization: Bearer [Alpha session]
HTTP/1.1 200 OK
{ "tenantId": "tenant_alpha", ... }
MODIFIED ID / TENANT BETA EXPOSED
GET /api/v1/invoices/inv_demo_1053
Authorization: Bearer [same Alpha session]
HTTP/1.1 200 OK
{ "tenantId": "tenant_beta", ... }
Root cause and recommended fix
The data lookup used only invoiceId. Scope every query to the authorized tenant
and object, for example by selecting on both tenantId from the trusted session and
invoiceId. Apply the same policy to download, update, delete and export routes.
Unpredictable identifiers are useful defense in depth, but are not authorization.
Retest criteria
Tenant Alpha must receive 404 Not Found or 403 Forbidden for every
tested Tenant Beta invoice identifier, while legitimate Tenant Alpha access continues
to work. Tests should cover sequential and random identifiers, all user roles and each
endpoint that accepts an invoice reference.
08 / LIMITATIONS
How to read this report
A penetration test is a time-bounded assessment of the stated assets, version and access
available during testing. It reduces uncertainty but cannot prove the absence of every
vulnerability. Changes after the assessment, untested integrations and excluded systems
may introduce additional risk.
This document contains fictional systems, identities, requests and results. It
demonstrates reporting structure only and does not describe an actual Hackers Company
client or completed engagement.