Full-scope penetration test of a US SaaS platform under OSSTMM v4. Six vulnerabilities identified across authentication, API security, and infrastructure — including a high-severity account takeover path. Re-test conducted to validate remediation.
Service Stories is a US-based SaaS platform providing service ticket and operations management tools. The engagement covered unauthorized web application and external service testing across their production and staging environments, conducted under the OSSTMM v4 methodology.
The engagement followed the full OSSTMM phase structure — beginning with posture review and DNS enumeration, moving through emanation analysis to identify the organization's digital footprint, then controlled interaction and intervention testing against live endpoints.
DNS enumeration across all subdomains. Infrastructure mapping — Cloudflare, AWS ELB, Cognito auth endpoint. API version fingerprinting via Censys. Confirmed staging and production API versions and deployment timestamps.
Employee identification via LinkedIn. Email address pattern enumeration. IP abuse database cross-reference. Both IPs flagged on AbuseIPDB for scamming, phishing, and SSH brute-force activity.
Port scanning on production and staging API endpoints. Unauthenticated API endpoint testing — sign-in, sign-up, token refresh. 2,890 login attempts to test brute-force controls. User enumeration via registration endpoint. Sequential ID analysis via repeated registrations.
Account lockout bypass testing. Refresh token persistence across security events. Email change workflow exploitation. Full account takeover chain demonstrated against Cognito accounts.
The application failed to revoke or rotate refresh tokens following security events — including explicit logout, account lockout, email change, and password reset. A refresh token issued in an earlier session remained valid and usable after multiple authentication cycles and session termination events.
Using a captured refresh token, it was possible to continuously obtain new access tokens and maintain authenticated access indefinitely. Combined with the email change functionality — which allowed replacing the registered email and completing verification via attacker-controlled email — this enabled full account takeover including access to billing, credit card information, and company data.
The application also failed to notify the legitimate user when their email address was changed. This vulnerability affected Cognito accounts only, not Google SSO accounts.
The sign-in API endpoints on both staging and production applied no rate limiting or lockout controls on login attempts. During testing, 2,890 login attempts were submitted without triggering any defensive response — no CAPTCHA, no lockout, no throttling.
This allowed unlimited automated credential stuffing and brute-force attacks against any known or enumerated account. The absence of controls on both production and staging environments indicated the issue was systemic rather than a configuration oversight.
The application backend, hosted on AWS Elastic Load Balancer, was directly accessible via public IP addresses on both production and staging environments — bypassing Cloudflare CDN and WAF protections entirely.
Requests sent directly to the backend IP returned identical responses to domain-routed requests. The backend also processed requests when supplied with arbitrary Host header values without restriction, compounding the exposure. Attackers could interact directly with backend services, removing reliance on any edge-layer protections.
The sign-up API returned distinct responses for existing versus non-existing email addresses. When a registration attempt used an email already associated with an account, the endpoint returned a specific error message confirming account existence. This allowed enumeration of valid user accounts using the email addresses identified during the emanation phase.
The registration endpoint returned the newly created user's sequential integer ID in the response body. By registering multiple test accounts, it was confirmed that IDs incremented predictably. This disclosed the approximate total user count and enabled construction of a complete user ID list — useful for future IDOR-based attack paths or targeted enumeration.
When a sign-in or sign-up attempt was made with a password shorter than the minimum requirement, the API response explicitly stated the minimum length constraint: "Too small: expected string to have >= 10 characters." This information assists attackers in optimizing brute-force dictionary attacks by eliminating passwords below the known minimum length.
Following the initial report, the client implemented fixes across their infrastructure and authentication stack. A structured re-test was conducted to validate each finding, confirm remediation, and identify any new issues introduced during the fix process.
| Finding | Status | Notes |
|---|---|---|
| Login brute-force | ✓ Pass | HTTP 429 returned at 10th failed attempt. Rate limiting confirmed on both environments. |
| Direct backend IP access | ✓ Pass | Direct connections to backend IPs timed out on both production and staging. Cloudflare proxy now enforced. |
| Password policy leakage | ⚑ Partial | Fixed on UI. API response still exposes minimum length constraint. Generic error message not yet implemented. |
| User enumeration | ✓ Pass | Registration responses normalized for existing and non-existing accounts. Email confirmation flow implemented. |
| Sequential user ID exposure | ✓ Pass | User IDs no longer exposed in registration response. Only confirmation message returned. |
| Refresh token — explicit logout | ✓ Pass | Refresh token correctly invalidated on explicit logout. |
| Refresh token — forced logout | ⚑ Residual | Refresh token remains valid when session is force-terminated due to suspicious activity. Revocation on security events not yet implemented. |
| Account takeover chain | ✓ Pass | Email change now requires old password and sends verification to original address. Wrong password triggers immediate forced logout. |
Password policy enforcement accepts common patterns such as "Password123!" despite meeting length and complexity requirements. A password blacklist or common-password rejection mechanism is recommended.
The re-test confirmed that the most critical infrastructure and authentication vulnerabilities were successfully remediated. The application's security posture improved substantially between the initial test and re-test.
Infrastructure hardening (Cloudflare proxying, port filtering) was fully effective. Authentication controls improved substantially. Two residual token-handling issues and one new password policy weakness remain for the next remediation cycle.