All posts
The RCE hidden behind a forgotten endpoint

The RCE hidden behind a forgotten endpoint

Some of the best findings come from not giving up when the obvious path is blocked.

I was working on a private bug bounty program with a broad scope. During reconnaissance, I found a subdomain running an internal application. The login page was public, but registration was disabled. No obvious way in.

I pulled the JavaScript files from the login page looking for hardcoded endpoints or API calls. Nothing useful. Dead end.

Most people would move on at this point. I almost did. But then I checked the subdomain enumeration results from my recon tools.

![RCE discovery flow diagram](rce-discovery-flow.svg)

One subdomain stood out. If the application was running at app1.domain.com, the API was at app1api.domain.com. The naming pattern was obvious once you saw it.

I started fuzzing the API subdomain. Standard directory brute-forcing, looking for endpoints that might not be properly locked down. After cycling through wordlists, one path returned a different response: /company/registertest.

ffuf -u https://app1api.domain.com/company/FUZZ \
     -w raft-large-words.txt -mc 200,302 -fs 0
...
registertest            [Status: 200, Size: 412]

The endpoint name told the story. It was a test registration endpoint, probably left over from development. Someone had built it to make testing easier and never removed it when the application went to production.

I tested it. It worked. I could create accounts on an application that wasn't supposed to allow registration.

At this point, I had a valid finding. Unauthorized account creation through a forgotten development endpoint. Low to medium severity depending on how the program scored access control issues.

I didn't report it yet.

The scope was *.domain.com. That meant everything under the domain was fair game. I had access to the application now. The question was whether there was something worse inside.

I registered an account, logged in, and started mapping the application's functionality. Standard testing process. Check the features, look at the network traffic, examine the JavaScript for client-side logic.

In one of the JS files, I found an AJAX call that stood out. It was hitting a PHP file with a parameter called "function". The parameter value was being set dynamically based on user interaction.

$.post('/ajax/handler.php', {
    function: action,  // set from the clicked button
    args: JSON.stringify(args)
}, ...);

That's a red flag. A parameter named "function" in a request to a PHP endpoint usually means someone is doing something dangerous with user input. Either calling functions directly or using eval-style patterns that execute code.

I tested it. Sent different function names. Tried system commands. It worked.

POST /ajax/handler.php HTTP/1.1
Host: app1.domain.com
Cookie: PHPSESSID=...

function=system&args=["id"]
HTTP/1.1 200 OK
Content-Type: text/plain

uid=33(www-data) gid=33(www-data) groups=33(www-data)

Remote code execution. Full command execution on the server. Critical severity. The kind of finding that gets prioritized immediately.

The chain was straightforward once you laid it out:

  1. Forgotten development endpoint allows unauthorized registration
  2. Registration grants access to internal application
  3. Internal application has RCE vulnerability in authenticated functionality

Report the first finding by itself? It's valid but limited in impact. Chain them together? It's a critical compromise of the entire application.

This is what impact escalation looks like in practice. You find one weakness, use it to gain access, then find the real vulnerability inside. The first issue is the key that opens the door. The second is what makes it worth walking through.

I've seen researchers report findings too quickly. They find the first vulnerability, submit it immediately, and miss the bigger picture. Then someone else reports the chain a week later and gets credited for the critical.

The lesson isn't to sit on findings indefinitely. It's to think about scope and impact before hitting submit. If the program allows broad testing and you've found a way in, spend a few hours looking for what else might be hiding inside. You might find nothing. You might find something worse.

In this case, I would have reported the registration endpoint even if I hadn't found the RCE. But I gave myself a few hours to test first. That decision turned a medium-severity access control issue into a critical remote code execution.

The forgotten endpoint was careless. The RCE was worse. Together, they demonstrated a complete failure of security controls. That's the finding that matters.

Development endpoints should never make it to production. Function parameters should never take arbitrary user input. These are basic security principles, and they get violated constantly. When they stack up in the same application, the impact multiplies.

That's what makes bug bounty work interesting. You're not just looking for individual vulnerabilities. You're looking for chains, combinations, patterns that compound severity. The researcher who sees those connections is the one who finds the critical issues.

Want me to find this in your app, or learn to find it yourself?

Request a pentestBook mentoring
← PreviousThe single quote that leaked database credentialsNext →The uppercase letter that bypassed authorization