From Username Enumeration to Subscriber PII: Chaining 3 Weak Findings in a Telecom Ecosystem

Severity: Medium
Bounty Awarded: $560
Program: Private Bug Bounty
Most hunters have encountered login enumeration and immediately deprioritized it.
Different response.
Different redirect.
Different wording.
You confirm the bug, think “low at best”, maybe submit it, maybe do not.
This write-up is about one of those findings.
In isolation, it was weak.
A username enumeration issue on a telecom login flow that realistically deserved low severity, or an arguable medium if triage felt generous.
No authentication bypass.
No direct account access.
No PII exposure.
No password reset abuse.
Just subscriber validation.
The interesting part came from chaining.
Not into an in-scope ATO.
Into an ecosystem.
The final chain looked like this:
/auth/validate-login
↓
Confirmed subscriber
↓
Voucher OTP generation
↓
Leaked OTP retrieval
↓
Voucher authentication
↓
/api/v1/integrator/login_redirect/{id}
↓
Subscriber-linked PII exposure
Recon: Following the Authentication Flow
The initial signal came from the authentication workflow.
During normal login interaction, the application performed a validation step before continuing authentication.
Instead of immediately requesting credentials, the flow first validated whether the supplied phone number existed.
The request looked roughly like this:
POST /auth/validate-login HTTP/2
Host: [REDACTED]
Content-Type: application/x-www-form-urlencoded
Cookie: laravel_session=[REDACTED]
_token=[REDACTED]&username=05XXXXXXXX
Nothing unusual at first glance.
Typical Laravel auth flow.
CSRF token.
Session cookie.
Phone number passed through username.
The interesting part was the response.
Finding #1: Username Enumeration via /auth/validate-login
The endpoint behaved differently depending on whether the subscriber existed.
Existing Subscriber
Submitting a valid number:
HTTP/2 200 OK
Content-Type: text/html
Response (redacted):
<div class="auth-container">
<form id="login-flow">
...
</form>
</div>
Observed behavior:
authentication flow continued
subscriber recognized
password/OTP state rendered
Non-Existing Subscriber
Submitting an invalid number:
HTTP/2 200 OK
Content-Type: text/html
Response:
<div class="register-container">
<h1>[REDACTED]</h1>
<p>[REDACTED]</p>
</div>
Observed behavior:
registration flow rendered
distinct UI state
predictable content difference
The signal was deterministic.
No timing attack.
No statistical guessing.
No race condition.
Simple response diffing.
Pseudo-logic:
if "register-state-marker" in response:
exists = False
else:
exists = True
That alone was enough to validate telecom subscribers reliably.
At this stage:
Impact = weak
Realistically:
Low severity.
If I had reported only this:
“User enumeration exists”
It probably ends there.
Why Telecom Enumeration Is Different
Enumeration on telecom assets is easy to underestimate.
Phone numbers are not disposable usernames.
They often act as shared identity keys across:
customer portals
vouchers
loyalty systems
rewards platforms
billing
partner services
mobile APIs
Once you can answer:
“Does this subscriber exist?”
You remove uncertainty.
That matters more than people think.
Without enumeration:
056XXXXXXX ?
059XXXXXXX ?
050XXXXXXX ?
054XXXXXXX ?
Everything is guesswork.
With enumeration:
056XXXXXXX → valid subscriber
059XXXXXXX → invalid
050XXXXXXX → valid subscriber
054XXXXXXX → invalid
Now targeting becomes deterministic.
This changed my next step.
Instead of escalating the enumeration directly, I started mapping adjacent assets.
Same branding.
Shared auth assumptions.
Similar phone-number workflows.
Typical telecom ecosystem sprawl.
That led to a connected voucher platform.
Importantly:
It was out of scope.
Many hunters stop here.
I usually do not.
Not for exploitation.
For impact modeling.
Because OOS weaknesses often explain why an in-scope bug matters.
Pivot: Mapping Identity Reuse
The first question was simple:
Does the same subscriber identity exist in the voucher ecosystem?
The answer was yes.
The voucher platform accepted the same subscriber phone numbers during authentication flows.
That immediately made the enumeration bug more interesting.
Because now:
validated telecom subscriber
=
validated voucher user
The enumeration finding had quietly become a targeting oracle.
Still not severe.
But now useful.
The next step was checking how authentication worked inside the voucher ecosystem.
The login flow relied on OTP verification.
Typical process:
submit subscriber phone number
generate OTP
validate OTP
establish authenticated session
Normally, this would still be annoying to abuse at scale.
You would need:
valid numbers
working OTP delivery
timing
access to SMS
But this is where the second finding appeared.
Finding #2: OTP Exposure via /api/v1/otp
While testing the voucher authentication flow, I noticed the platform relied entirely on SMS OTPs for login.
Typical flow:
phone number
↓
OTP generated
↓
SMS delivery
↓
OTP verification
↓
authenticated session
At first, this looked standard.
The important detail was that the same subscriber phone numbers validated through the telecom login flow also existed inside the voucher ecosystem.
Meaning the first bug already solved a major problem:
target validation
Instead of guessing random numbers, I now had confirmed subscribers only.
The voucher authentication flow started with OTP generation:
POST /api/v1/otp/send HTTP/2
Host: voucher.[REDACTED]
Content-Type: application/json
{
"channel": "sms",
"receiver": "05XXXXXXXX",
"action": "LOGIN_OTP"
}
Response:
{
"is_successful": true,
"data": {
"identifier": "[REDACTED]"
},
"message": {
"title": "Success",
"message": "OTP generated successfully."
}
}
Nothing unusual yet.
The problem appeared during OTP handling.
A separate endpoint exposed OTP-related data in a way that broke the trust assumption behind SMS verification.
Redacted request structure:
GET /api/v1/otp HTTP/2
Host: voucher.[REDACTED]
Authorization: Bearer [REDACTED]
Response shape:
{
"is_successful": true,
"data": {
"data": [
{
"identifier": "[REDACTED]",
"otp_code": "[REDACTED]",
"action": "LOGIN_OTP",
"expiration_time": "[REDACTED]"
}
]
}
}
The key issue:
The platform exposed active OTP context that should never have been retrievable in this manner.
In practice, this collapsed the SMS trust boundary.
Instead of:
generate OTP
↓
wait for victim SMS
↓
manually receive code
The flow became:
generate OTP
↓
retrieve OTP context
↓
complete auth
At this stage, the voucher compromise became practical.
But there was still a limitation.
Authenticated access alone did not necessarily expose meaningful telecom subscriber context.
The next question became:
What does the voucher platform trust downstream?
That led to the third finding.
Finding #3: Subscriber Context Exposure via /api/v1/integrator/login_redirect/{id}
After authentication, I continued tracing authenticated requests and integration behavior.
One endpoint immediately stood out:
POST /api/v1/integrator/login_redirect/{id} HTTP/2
Host: voucher.[REDACTED]
Authorization: Bearer [REDACTED]
The endpoint appeared to broker authentication between systems.
The naming alone was interesting:
login_redirect
That usually means one system trusts another to establish user context.
Redacted response structure:
{
"status": "ok",
"data": {
"access_token": "[REDACTED]",
"refresh_token": "[REDACTED]",
"customer": {
"id": "[REDACTED]",
"name": "[REDACTED]",
"email": "[REDACTED]",
"phone": "05XXXXXXXX",
"customer_identifier": "[REDACTED]",
"reference": "[REDACTED]",
"subscription_metadata": "[REDACTED]"
}
}
}
This was the moment the chain became interesting.
The voucher ecosystem was not isolated.
It trusted subscriber context from the telecom platform.
Which meant successful authentication in vouchers exposed subscriber-linked information originating from the larger ecosystem.
The important part here was not the endpoint itself.
It was what the earlier findings changed.
Without enumeration:
random numbers
↓
poor targeting
↓
low reliability
Without OTP exposure:
confirmed subscriber
↓
blocked by SMS possession
Combined:
confirmed subscriber
↓
voucher auth
↓
subscriber context
↓
PII exposure
This transformed the original finding.
The in-scope bug stopped being:
“You can tell if an account exists.”
And became:
“You can deterministically identify real subscribers and materially improve downstream compromise leading to subscriber PII exposure.”
That is a very different risk discussion.
Why the Medium Felt Unfair
I understand why the report landed as Medium.
Strictly speaking:
the enumeration itself was weak
the downstream issues were out of scope
no direct compromise occurred on the primary platform
From a program perspective, that makes sense.
But from an attacker perspective, the chain mattered more than the individual bugs.
The in-scope issue solved the hardest problem:
certainty
Instead of wasting effort on random telecom ranges, an attacker could focus entirely on verified subscribers.
That dramatically increased reliability.
And reliability is often what separates:
theoretical abuse
from
practical abuse
Hunter Takeaways
1. Enumeration Is Often More Valuable Than It Looks
Especially in:
telecom
fintech
loyalty systems
identity-heavy ecosystems
Because identity is shared everywhere.
2. OOS Findings Still Matter
Not for payout arguments.
For impact modeling.
Ask:
Does this make my in-scope finding more dangerous?
Sometimes the answer upgrades the whole story.
3. Stop Thinking in Single Bugs
The best findings are often:
weak bug
+
weak bug
+
weak assumption
=
real impact
This chain was exactly that.
None of the findings looked especially impressive alone.
Together, they became something much harder to dismiss.
Final Thoughts
If I had reported /auth/validate-login immediately, this would have probably ended as a low-quality Medium and disappeared into the backlog.
The useful part was continuing to dig.
Not because I expected a critical.
Because telecom ecosystems tend to reuse identity everywhere.
That assumption paid off.
The biggest lesson from this case:
Sometimes the bug is not the vulnerability itself.
Sometimes the bug is simply the thing that makes the next vulnerability finally practical.






