Web Application Pentest Report
Acme SaaS Platform — Sample / Sanitized
Report version: 1.1
Assessment period: [sanitized]
Classification: Confidential
Scope
Web application at app.[redacted].com, authenticated and unauthenticated surfaces, REST API at /api/v2/, OAuth 2.0 flow, webhook configuration, and administrative dashboard. Mobile applications and infrastructure out of scope.
Executive Summary
This assessment identified 11 findings across the in-scope surfaces, including two critical issues and three high-severity vulnerabilities. The most significant findings involve broken object-level authorization across the multi-tenant API and a JWT algorithm confusion vulnerability that allows authentication bypass. Both are fully exploitable and confirmed with proof.
The issues identified represent genuine security boundaries that require remediation before the next major customer deployment or enterprise sales cycle. Remediation guidance is provided for each finding. A retest is included within 30 days of this report.
2
Critical
3
High
4
Medium
2
Low / Info
Technical Findings (excerpt — 3 of 11)
Broken Object Level Authorization in /api/v2/projects/{id}
Summary
An authenticated user can access project resources belonging to any other organization by manipulating the project ID in the request path. Authorization is checked at the route level but not at the object level, allowing horizontal privilege escalation across all tenant boundaries.
Steps to reproduce
- 1Authenticate as User A in Organization A. Note the project ID of a resource you own: /api/v2/projects/1042
- 2Authenticate as User B in Organization B.
- 3As User B, send: GET /api/v2/projects/1042
- 4Response: 200 OK with full project data from Organization A.
Impact
Any authenticated user can read, modify, or delete project data from any other organization. Full multi-tenant data isolation failure.
Remediation
Implement object-level authorization checks in the project retrieval handler. Verify that the requesting user's organization_id matches the project's owner_organization_id before returning any data. This must be applied at the data access layer, not only at the route middleware level.
JWT Algorithm Confusion — RS256 to HS256 Downgrade
Summary
The token validation endpoint accepts tokens signed with HS256 using the application's public RSA key as the HMAC secret. An attacker who obtains the public key (exposed at /api/.well-known/jwks.json) can forge valid tokens for any user ID.
Steps to reproduce
- 1Retrieve the public key: GET /api/.well-known/jwks.json
- 2Extract the public key bytes.
- 3Craft a HS256-signed JWT with arbitrary sub claim, signed using the public key bytes as the HMAC secret.
- 4Send the forged token as a Bearer token to any authenticated endpoint.
- 5Response: 200 OK with data for the user ID specified in the forged token.
Impact
Full authentication bypass. An attacker can impersonate any user, including administrators, by crafting a valid-looking JWT without the private key.
Remediation
Explicitly specify the allowed algorithm in the JWT validation library configuration. Never accept 'algorithm from header'. Reject any token whose header algorithm does not exactly match the expected algorithm (RS256). Rotate all private keys immediately.
Stored XSS via Webhook Payload Name Field
Summary
The webhook configuration name field is stored without sanitization and rendered without escaping in the admin dashboard. An attacker with webhook configuration access can inject script payloads executed in the context of any admin viewing the webhook list.
Steps to reproduce
- 1Navigate to Settings → Webhooks → Add webhook.
- 2Set name to: <img src=x onerror=alert(document.cookie)>
- 3Save.
- 4Navigate to the admin view of webhooks (requires admin access or another user with admin privileges to view).
- 5XSS payload executes in the admin's browser.
Impact
Session hijacking of admin users. Requires the attacker to have webhook configuration access and the victim to be an admin viewing the webhook list.
Remediation
Sanitize the webhook name field at storage time using a well-maintained HTML sanitization library (DOMPurify for client-side, bleach or similar for server-side). Separately, apply output encoding in the template layer where webhook names are rendered.
This is what your report looks like
Every finding we deliver has this level of detail: reproduction steps, confirmed impact, and specific remediation. No scanner noise. No vague recommendations.