Was planning on using spaces for my APCSA class and show it to my peers, teacher asked me if the code was secure and asked me to check it… i ended up finding a CSRF bug in the admin panel. Here’s how.
The Bug
Admin endpoints read auth tokens from the request body instead of headers:
// src/middlewares/admin.middleware.js line 6
const { authorization } = req.body; // bad
// vs everywhere else
const authorization = req.headers.authorization; // good
Why does this matter? HTML forms can set body data, but they can’t set custom headers. So I can make a form on any website that submits to their admin API.
The Attack
<form method="POST" action="https://spaces-api.com/api/v1/admin/users/1/update">
<input type="hidden" name="authorization" value="STOLEN_TOKEN">
<input type="hidden" name="is_admin" value="true">
<button>free robux</button>
</form>
If an admin clicks that button (or I auto-submit it with JS), their browser sends the request. No CORS issues, no preflight - just a normal form submission.
Proving It
Saved the HTML locally, opened it, clicked the button:
Origin: null- request came from a file, not their siteSec-Fetch-Site: cross-site- browser confirmed it’s cross-origin- Response:
401 Invalid authorization token- server processed it, just rejected the fake token
With a real token, this executes. Game over.
How Would You Get The Token?
The OAuth flow leaks it in the URL fragment after login (/#oauth_success=true&user_data={"authorization":"xxx"}). This gets saved in browser history, can be logged by analytics, or leak via Referer header. Any XSS would also grab it.
The Fix
One line change:
- const { authorization } = req.body;
+ const authorization = req.headers.authorization;
Status
Reported on 15-01-26
On 15-01-26 Ivie (the maintainer of Space) contacted me stating:
“Hey End!
Re: the two security bounties you submitted
Neither are these are eligible for a payout, due to spaces being in a private beta state.
However, even if it was in production, they would not likely get a payout as:
The admin csrf requires you to already have an admin token, and if you had an admin token you could just use the admin endpoints, no csrf needed
Both will be fixed before spaces goes to production though, thanks for the report!”