agenticjobs signs people in with a magic link. No passwords. On a laptop there is no mail provider, so the board prints the link to the server log instead of sending it. That is a normal convenience.
Yesterday I ran signup against the live board and got this:
https://agenticjobs.work has no mail server configured, so it logged the link
instead of sending it.
The obvious read is that a key was missing. The actual problem was worse.
The config had an SMTP_URL field. It was declared in the Config type, read from the environment, and threaded through both login routes. Nothing in the codebase could send mail. No mail client, no SMTP library, no HTTP call to a provider. The variable existed and the feature did not.
So config.smtpUrl === null was true on every instance that has ever run. Every board took the "no mail server" path. And delivered in the API response was not a fact about a send, it was smtpUrl !== null, which was always false.
That part is just an unfinished feature. Here is the part that matters.
The login page had this:
<LoginPage sent={email} {...(config.smtpUrl === null ? { devLink: url } : {})} />
Because the condition was always true, the page rendered a working sign-in link into the HTML for whoever typed the address. Not for the owner of the address. For whoever typed it. And consumeMagicLink calls ensureUser, so the account does not need to exist first. Type an address, get a link, become that person.
A dev-only branch is only dev-only if something makes it false in production. Nothing did.
The fix itself is boring. Mail goes through Resend now, using the emailer package we already had. What is worth keeping is the rule: the link only ever reaches the server log, never the browser, on both the unconfigured path and the send-failed path. There is no condition under which a credential gets rendered into a page.
Two smaller things came out of it.
The email a terminal asks for now carries that terminal's code, and the subject says "Approve your terminal". A device flow where you cannot match the email against the request in front of you is one where a link phished out of an inbox approves someone else's session just as well as yours.
And delivered now means a send that happened. A provider returning 403 for an unverified domain is not a delivery, and neither is having no provider at all. Both are false, and the page says the board could not send rather than claiming an email is on its way. I found that path by accident: Resend rejects example.com recipients, so my first probe failed and showed me the error copy was right.
Then there was the directory. agenticjobs.work is both a board and the directory other boards announce to, so it names itself in DIRECTORY_URL. Turning announcing on put the board in its own listing.
That guard went in three places, because each one has a different attacker: the heartbeat, the CLI, and the announce endpoint, which refuses its own origin from anyone. Guarding only the sending side would let a third party list the board on its behalf.
Refusing new self-announcements does not remove the row an earlier one left, though, and the live board had one. So the sweep drops it now. A board that turns the guard on later heals itself instead of needing someone to reach into the database.
0.3.0 is out. Minor rather than patch because SMTP_URL is gone and RESEND_API_KEY replaces it.
Written with AI assistance.
Top comments (0)