Three weeks ago, a reader pointed out that RamenHire's RLS policies treated "signed in" as a proxy for "admin" — safe only because no real user login existed yet. I logged it as a deliberately deferred finding: real, but not exploitable until the day real accounts existed. This week, that day arrived, and so did the moment to find out whether the deferral was actually safe.
What shipped
Real per-company accounts. Email/password auth, a proper session, a settings page, and — the actual point of all of it — self-service control over your own listings: create, edit, delete, no email to me required. This is the direct answer to the thing that started this whole thread of work: a company that asked me to take their listing down, because they had no way to do it themselves.
Underneath that: an is_admin flag, real Row Level Security scoping every table by ownership instead of a blanket "any signed-in user," a soft-delete and purge system with a real grace period, and a security audit that re-tested the RLS closure adversarially rather than trusting the sprint's own step-by-step checks — including trying to reassign a listing's ownership via a raw, forged request directly against the database, bypassing the app entirely. Rejected, correctly, at the database layer.
The part that actually scared me
A few days after the sprint "finished," a different reader published a post with a title that stopped me cold: this endpoint has auth, the tests are green, it still lets a user hand themselves admin. The pattern: a route checks that you're logged in, then writes your request body into the database without checking which fields it's writing — so a client can slip in a privileged field alongside a legitimate one, and it just gets accepted.
Here's why that pattern is uniquely dangerous in this codebase specifically: every write route I have goes through a service-role client, by design, for reasons that made sense at the time. But a service-role client bypasses Row Level Security entirely. All the RLS work from the sprint above — meaningless, for these routes, if any of them forwarded the request body instead of picking specific fields out of it.
So before anything shipped, I checked every route this sprint touched, the same way the post described: crafted a request with legitimate fields sitting next to is_admin: true, status: "approved", someone else's company_id. Sent it for real, against a real database, and checked what actually landed — not whether the request succeeded, but what the row looked like afterward.
Every route held. Every privileged field was silently dropped; only the legitimate fields ever changed. Not because I got lucky — because every route was written to explicitly pick the fields it expects, not to trust the shape of whatever arrived.
I don't think I would have thought to test this specific thing on my own. I've been building this in the open long enough now that I've stopped being surprised when the most useful pressure-testing comes from someone else's post, not my own checklist.
What's still open, on purpose
Not everything gets fixed just because it got found. A couple of things from this pass are logged as deliberately accepted for now rather than fixed: login rate limiting is IP-based (an email-keyed backstop got added since, closing the gap a distributed attacker could otherwise use); there's no persistent audit trail of what the automatic purge job actually deletes, just Vercel's own function logs. Neither blocks anything today. Both are written down, dated, so they don't quietly become "we forgot" later.
The honest number
Real registered companies, after all of this: still building toward the first one. This sprint didn't produce a growth result — it produced the thing that has to exist before a growth result means anything. A company controlling their own listing isn't a nice-to-have; it's the baseline a real company should expect before trusting a platform with anything at all.
Top comments (0)