At some point, a different developer was told to consume this endpoint, send the related email, and tell the end user (browser client) that the email was sent. This second developer is not part of the "senior services team" who designed the above API, which is perfectly valid. Instead, this is a junior developer taking on their first task at the company. "Take this password reset API endpoint, and integrate it". In addition to queuing the password reset email with the token embedded within it, they also accidentally proxy the password reset service's payload to the browser. No intermediate or senior develop reviewed this new employee's PR; if they did bother to look at it, they only checked for coding standard violations (eg. indentation), without taking the effort to understand the logic of the code.
This is actually extremely common, unfortunately. The server-side layer that directly interacts with clients (ie. browsers) is generally delegated to the most junior developers, because it's menial and uninteresting work to connect the backend services to the browser. The current senior developers spent years working on that kind of garbage already, and they'd rather work on the "more interesting/advanced" backend work. Thus, the junior developers whose skills aren't yet honed are stuck–typically unsupervised–working on the front-facing components.
Also, this routinely happens at companies which rush every feature out the door with modern "agile" practices. The sprint is almost over! Quick, deliver all features by tomorrow to keep up our velocity and avoid a sprint review with negative feedback! Just merge it and push to prod without QA on a Friday at 4pm!
If only the above was a comedy routine, rather than what it truly is: the genuine reality at a large number of companies.
Hacker News seems to assume juniors are useless, from the comments I've seen to date - but they should be able to _think_ and solve problems, even if they're less experienced at interacting with stakeholders, designing system architecture etc.
Sooo... what's the one thing we need this token to be. Secret.
OK, let's just return it to the one person in the whole world we don't want to have it.
Mmmm is it lunchtime...?
Issue #2141 - implement password reset: After answering secret question user should see password reset link.
Issue #2534 - send email with password reset link.
Issue #2743 - remove password reset link from web page
Issue #3892 - replace secret question with email address input
But seriously, I'm sure it was made by people that just didn't stop to think about security and "it works, so we're done here" Then, as a business you're not going to try and fix it if the software already works. That would be pure cost.
Again, yes, the bug is very bad. Software is complex, and humans are humans, and it's not difficult to imagine how these bugs occur.
Whatever API this is using, there's zero reason to show any information about the request other than "we didn't die, so it should succeed". Beyond even showing it, there's zero reason for a password reset API to respond to the request with the secret at all. If it needs to return anything identifying about the request, it should be some identifier that is NOT the secret, which can be used to pull up general info about the request later if needed (time generated, whether it was used, is it expired, etc). Extra points if the access credentials to any back-end API the request page uses can't even request the secret key from a request.
A sane API makes it very hard for something like this to happen. Often that takes an inversion of thinking, so instead of making an API as useful as possible and return as much data as efficiently as possible, you make to make it as secure as possible, which means returning as little data as possible to satisfy the specific needs of the use case, and different locked down credentials for specific use cases.
This is also compounded by the drive to artificially complicate software stacks (microservices, etc) and "silo" developers into their own little bubble where they only work on a small aspect of the system and never have a need (nor the mental capacity - due to intentionally complicated stacks with dozens of microservices in various languages) to look at the big picture.
Just saying that this might have been one reason for such data to be returned.
You may not have access to the database if you're doing frontend testing using headless browser.