← All notes

One Day, Eight Repositories

This is a log of one day. Not a highlight reel, a log, including the parts that were us fixing our own mistakes. Eight codebases moved. Here is what actually happened in each, and what it cost.

The authentication service got audited

A full security review of the password reset API, with the fixes shipped the same night rather than filed for later.

The server-side request forgery work is the part worth describing. Anywhere a customer supplies a destination that our server will then call, that destination has to be checked, and the naive version of that check misses more than it catches. The gaps closed today: the cloud metadata endpoint, which is the standard way to steal credentials out of a hosting environment; the whole loopback range rather than just the obvious address; IPv6 loopback; addresses disguised in decimal or hexadecimal notation; and carrier-grade NAT ranges. It also stopped wrongly blocking a block of legitimate public addresses, which is the quieter half of getting this right.

The part I would not have thought to do: it resolves the hostname and checks every address it points at, at the moment of use rather than when the value was saved. A name the customer controls can point somewhere safe when you check it and somewhere else a minute later. That is the actual attack, and validating once is validating at the wrong time.

That service now runs 195 tests. None are marked as work for later.

Also today: it serves through a database outage instead of dying, it names bad configuration at boot rather than failing mysteriously later, email delivery is verified for real rather than assumed, and the suite runs on every push.

A domain went live

The monitoring platform now answers on its own name rather than a hosting subdomain. Small thing, one commit, but it is the difference between a project and a product.

It also stopped crashing on bad configuration, and it now accepts the connection variable under the name every other service uses. That one was ours: the same setting had a different name in almost every project, and each name was reasonable when it was chosen. Together they were a trap, because setting the right value under the wrong name looks exactly like doing it correctly.

The privacy tool got its mail path working

Not "exists", working. There is a difference and it is usually about a day of effort.

The detail I liked: when mail bounces, the recipient's address no longer goes into the log. Logs get copied into places nobody is thinking carefully about and they outlive the systems that wrote them, so an address in a log line is an address you have published to your future self and everyone who ever reads that file. For a tool whose entire job is removing personal information from places it should not be, leaking it into our own logs would have been a bad joke.

The landscaping site learned to check itself

A preflight check that names which setup stage is broken, rather than failing somewhere downstream and making you guess. Plus magic-link sign-in for the admin, borrowed from the auth service, and throttling on failed logins.

The portfolio reader stopped trusting itself

Contract addresses and chain identifiers had been typed into a table by hand. They look authoritative sitting there in the code and they are really just a guess.

Think about what a wrong one does. A mistyped address that happens to point at a real token returns a real balance under a confident wrong label. A wrong decimal place is a tenfold error in the total. None of it is visible from inside the app, which renders beautifully either way.

So it asks the chain instead: each token's symbol and decimal count read from the contract itself, and anything whose real identity disagrees with our label gets marked unverified rather than displayed as fact. It also learned nineteen more EVM chains, and it now reads balances from two different explorer dialects rather than depending on one.

And the day's actual embarrassment

The button on our own services page did nothing.

It was a plain mailto: link. On a phone that always works. On a desktop where no application is registered to handle mail, which is nearly everyone using webmail in a browser, clicking it does absolutely nothing. No error, no tab, no feedback. The front door of the funnel was dead for most desktop visitors and had been since the page went up.

It now still opens mail for people who have a mail app, and also copies the address, says so, offers a webmail link, and prints the address in plain text. Everyone leaves with a way to get in touch regardless of what their browser does.

Two more of the same kind. The site's navigation on a phone was seven links plus a toggle, wrapped across three lines, filling the entire first screen: someone arriving from a shared link saw navigation and no writing. And every link we posted to social previewed as bare text, because the site had no share image at all.

Four corrections

More interesting than the features.

Cost basis. We had written that a particular accounting method is what most tax regimes apply to a coin-to-coin trade. It is not permitted in the United States, which is where most of our readers are. Corrected at the top of the original post, in the code, and in full here.

Two lapsed claims on a security page, which had been true when written and quietly stopped being true.

A vulnerability reporting address that pointed at a mailbox which did not exist. If you are going to invite people to report problems, the address has to work.

Crypto payment, which was completely undocumented despite being accepted.

A correction you can see is worth more than a page that was never wrong, and a page that was never wrong usually means nobody checked.

The pattern, if there is one

Read the day back and almost every item is the same shape: something that looked fine and was not, found by comparing what the software claimed against what was actually true.

The table that was a guess. The button that did nothing. The mailbox that did not exist. The claim that used to be right. The variable name that differed between two projects. None of it was visible from inside the thing. All of it was found by checking from outside.

That is most of the job. The rest is typing.

Gunnar

Founder, Tofte Ventures LLC