A configuration file with the real password in it is not a sign of a careless team. It is what a team that shipped something under pressure in year one looks like in year six. On the day it was written there was one server and one developer, and putting the value in the file was the sensible thing to do.
Then the code gets copied onto laptops. It goes into backups. A contractor has access for three weeks. Somebody duplicates the file before an edit and commits the copy too. None of those are mistakes exactly, and the result is that a live production password exists in more places than anybody can list.
That is the actual problem. Not the file. The copies.
What we found
Files tracked alongside the code holding the production database password and credentials for several outside services — including a payment provider key and the credentials used to send email as the company.
Next to one of them, a second file with the same shape and “backup” in its name, holding another environment’s values. Somebody had made it before a change, years earlier, and it had been part of the codebase ever since.
Worth stating plainly because it is so common: every one of those was added by somebody solving a real problem quickly, and every one of them survived because nothing in the process ever asked the question again.
Moving them out
The software now reads its configuration from the environment it is started in — values handed to it when it runs, rather than read from a file that lives inside the code. The codebase holds an example file listing every value the software needs, with the values left empty. That example turns out to be genuinely useful on its own: it is the only complete list of what the software requires, and before this there was no such list anywhere.
The real values live in a managed store and are supplied at release time. The software never sees a file; a developer never sees the value.
A check runs before every commit and refuses one that contains something shaped like a credential. That is the part that stops this recurring in eighteen months, and it costs almost nothing.
The whole move took about a day. That is typical, and it is worth saying because the perceived size of this job is the reason it gets deferred for years.
The half that is not a day
Everything above changes what happens next. It changes nothing about what already happened.
The old values are still in the history of the codebase. Every copy anybody ever made still contains them. Every backup of those copies contains them. Rewriting history to remove them is possible, disruptive, and — this is the part people miss — does not reach the copies you do not control.
The only thing that actually closes it is changing the credentials. Change the database password, reissue the keys, and the values sitting in all those copies become worthless.
We want to be exact here, because it is the difference between a claim and the truth. On this system the storage was fixed and the rotation was not finished. New values went into the managed store, the software stopped reading them from a file, and several of the old credentials were still live at the time of writing, because reissuing them depends on outside providers and their schedules rather than on engineering.
That is an unsatisfying way to end a section and it is what happened.
What we would do differently
We led with the engineering. The engineering was the easy part.
Knowing what we know now, the first deliverable would be a rotation list — every credential in the file, who issues it, what breaks when it changes, and how long that provider takes — and the second would be dates against each item. The code change is a day and can happen at any time. The rotation is the thing with a lead time, and starting it last is exactly how it ends up unfinished.
If this describes your codebase
Ask for one thing: a list of every credential that appears anywhere in our source code or its history.
Then, for each one, the only question that matters: has this value been changed since it was last in a file somebody could copy?
If the answer is no, that credential is live in every copy, laptop and backup made since. Not necessarily in anybody’s hands — but you cannot say it is not, and that distinction is the whole thing.
If you want the code itself looked at rather than described to you, write and tell us what you have; the reply is free.