Keeping a Security Posture
The security work you do at the beginning of a build has a shelf life, and nobody tells you what it is. A posture is not a state you reach. It is a state you lose slowly.
Security gets talked about as something you achieve. You do the design work, you put the controls in, and then you have it. That framing is wrong in a way that matters, because a security posture is not a state you reach. It is a state you lose slowly, and the losing happens without anything appearing to go wrong.
I am early enough in this build that most of what I am about to describe has not happened to me yet, and that is exactly the point. The controls that catch decay have to be standing before the decay arrives, which means anticipating it rather than waiting to learn it. Some of this I have already lived. The rest I built for because I could see it coming.
Four things decay, and none of them announce themselves.
Your dependencies acquire vulnerabilities you did not introduce. The framework you chose is fine on the day you choose it. At some point somebody finds a flaw in it, and your application now contains that flaw without you having done anything at all. This is the most common way a well-built system becomes an insecure one, and it requires no mistake on your part.
I spent real time on a multi-major framework upgrade purely to clear vulnerabilities. Not a patch, two major versions, which means breaking changes, deprecated behavior, and a lot of things that worked yesterday not working today. There was no product benefit. Nobody asked for it. It was its own tracked piece of work rather than something folded into a feature, because folding maintenance into features is how maintenance stops happening.
Your credentials spread. A key starts in one place. Then it is needed in a second service, and a third, and a local environment, and a deployment configuration, and by the time you want to rotate it you are not entirely sure where all of it lives. Rotation then becomes an act of archaeology, and the failure mode is specific: you change one side and not the other.
I have done exactly that. A signing secret updated in one place and not the other meant every message between two systems failed authentication, for about thirty-six hours, silently. So rotation stopped being an edit and became a procedure. When a credential changes, every system holding it gets updated in the same sitting and each one gets verified before the work is considered done. Not later, not on a list.
Your configuration drifts. This is the one I did not see coming, and it is the one I would warn a builder about hardest.
Configuration that lives in a third party's dashboard is state you do not own and do not version. It is not in your repository, it does not appear in a diff, and nothing tells you when it changes. I had an event subscription switch itself off. Not deleted, not changed by me, simply no longer selected, which meant a category of message stopped arriving and nothing at all indicated a problem. No error, no log line, no failed record. The absence of an event looks exactly like the absence of anything happening.
Three separate configuration incidents in three days, all of which presented as broken software and none of which were. That is why every working session now starts with verification against reality rather than against memory. What is actually deployed. What the database actually contains. What the third-party configuration actually says right now. Fifteen minutes, before anything else, every time.
And whatever you switched off stays off. This is the quietest one and the most dangerous.
At some point you disable a control to unblock yourself. A rate limit that is making local testing painful. A validation that is rejecting your test data. A check that is firing on something you already know about. Entirely reasonable in the moment, and the moment passes, and the thing stays off, because nothing in the system is going to remind you.
So the rule is that anything disabled becomes a hard requirement to re-enable before the work that disabled it can close. Not a note, not a comment, a blocking condition. Temporary is the most permanent state in software, and the only defense I have found is refusing to let the work finish while the temporary state still exists.
Those four are the entire content of the upward steps in a maintained posture. There is nothing sophisticated in any of them.
What makes the maintenance actually happen is that the controls are structural rather than procedural. Every irreversible action passes through a gate that has to be consciously cleared. Every change is recorded, which means a mistake is discoverable rather than invisible. And the components carrying the most sensitive responsibility, identity and payments among them, are operated by companies whose entire business is that one thing, with dedicated security teams and incident processes standing behind them.
The cadence is the other half of it. When one secret changes, every secret gets calibrated. Not the one that changed, all of them, regardless of what I happen to be working on that day and with no exceptions, because the failure I described earlier happened precisely because a credential got treated as a single edit rather than as a set.
Time to build has never once outranked quality, completeness, or robustness on this project. That is not a statement about discipline, it is a structural decision: I removed the trade from the table, which means there is no schedule pressure available to spend against maintenance when maintenance is inconvenient. Every builder eventually faces the choice between shipping and hardening. The only reliable way I have found to win that argument is to not be having it.
Decay is worth describing concretely, because people picture a breach and that is not what it looks like.
A dependency three versions behind. A key that has quietly ended up in five places. A rate limit switched off to unblock a test. None of it is broken. Everything works.
It looks like a dependency three versions behind. A key that has quietly ended up in five places. A rate limit switched off to unblock a test and never switched back. A configuration that changed in a dashboard nobody has opened in months. None of it is broken. Everything works, users are happy, features are shipping, and the system is quietly less defensible every week than it was the week before.
That is the reason the maintained line in that chart has teeth in it rather than being flat. There is no version of this where you do the work once and it stays done.
If you are building something, the practical advice is to choose a cadence you can actually sustain rather than one that sounds rigorous. A dependency review you genuinely do every month beats a quarterly one you skip twice. A five-minute configuration check at the start of a session beats a formal audit you schedule and postpone. The failure I see described most often is not a weak control, it is a strong control nobody kept up.
A posture you maintain badly is worth more than a posture you established perfectly and then walked away from.
Selecting supply chain technology?
PreShiftIQ matches buyers to vendors on measured fit across TMS, dock scheduling, ELD, carrier vetting, and fleet management. Vendors pay for outcomes, never for influence, and the buyer match is free.
See how matching works at preshiftiq.com/how-it-works.
Next in the series: the parts that took longest, and why none of them were the parts I expected.

