Secure Coding for Teams Without a Security Hire
Earlier in this series
Founders ask me some version of the same question: "When do we need a security person?"
Later than you think — if your engineers pick up a small set of habits first. I say this as someone who lived it. At my own startup in Tallinn, I recruited and managed an international dev team, and there was no security hire because there was no budget for one. Security was a set of practices baked into how the team worked, or it was nothing. I have written about the program side of that in Building a Vulnerability Management Program from Zero. This piece is the coding side.
The honest claim: something like 20% of secure-development practice prevents the large majority of the failures small teams actually suffer. I laid out those failures in OWASP Top 10, Five Years Later — missing authorization checks, leaked secrets, stale dependencies, drifted configuration, homemade login. Here is the 20% that targets them.
1. Let the framework do the dangerous parts
The cheapest security decision your team will ever make is refusing to hand-roll what the framework already does safely.
Use the ORM or parameterized queries — never string-built SQL. Use the template engine's auto-escaping — never manual HTML assembly. Use the framework's session handling, CSRF protection, and password hashing. Use an established identity provider or auth library instead of custom login flows.
None of this requires security expertise. It requires a team norm: the safe default is mandatory, and deviating from it needs a written reason in the pull request. At my startup that single norm eliminated whole bug classes before anyone had to be clever. Modern frameworks encode years of security lessons; a small team's job is to not opt out of them.
2. Put authorization in one place
The bug I see most in small codebases is not a missing login check. It is a missing ownership check — the endpoint that confirms you are a user but not that the resource is yours.
These bugs breed when authorization logic is scattered, re-implemented slightly differently in every handler. Some handler will get it wrong, and each new endpoint is a new chance.
The fix is architectural and it is cheap if you do it early: one function, one middleware, one layer where the question "may this user do this to this object?" gets answered. Every handler calls it. Code review then has a simple, checkable rule — every new endpoint calls the authorization layer — instead of an impossible one ("think hard about access control").
If you adopt only one practice from this piece, adopt this one.
3. Treat secrets as radioactive
Credentials in a repository are a breach with a delay on it. Repos get cloned, forked, made public, shared with contractors. The secret outlives every one of those decisions.
The habit set is small. Secrets live in environment variables or a secrets manager, never in code or config that gets committed. A pre-commit secret scanner runs locally and in CI — these tools are free and take an afternoon to wire up. And when a secret does leak, the response is rotate, not delete — version control remembers everything, and so do the people who cloned it.
One more from hard experience with client codebases: anything shipped to a browser or mobile app is public. API keys "hidden" in client code are not hidden. We treated our own mobile app that way before launch, and the penetration test I directed confirmed it was the right assumption.
4. Make dependency updates boring
As I argued in the OWASP piece, outdated components are a scheduling failure, not a knowledge failure. The countermeasure is to make updating so routine it stops being a decision.
Concretely: lockfiles committed, so builds are reproducible. An automated scanner in the pipeline that flags known-vulnerable dependencies and fails the build on critical ones. Small, frequent version bumps — weekly or per-sprint — instead of heroic annual migrations. A short allowlist mentality for adding new dependencies: every library is code you now maintain without having written it.
Wiring the scanner into our build was the single highest-return automation of my startup years. It caught real issues, silently, forever, for one afternoon of setup.
5. Add five security questions to code review
You already have code review. That makes it the cheapest security gate you will ever own — if the checklist is short enough to be applied every time.
Ours fit in five questions:
- Does every new endpoint call the authorization layer?
- Is all input handled through the framework's safe mechanisms — no raw queries, no manual escaping?
- Any secrets, keys, or credentials in this diff?
- Are errors handled without leaking internals to the user?
- If this touches sensitive data, is it logged — and is the sensitive data itself kept out of the logs?
Five questions get asked on every pull request. Fifty get asked on none. Resist every temptation to grow the list; when a new check earns its place, an old one should usually leave.
6. Log enough to answer "what happened?"
Small teams skip logging because it does not ship features. Then something odd happens in production and there is nothing to look at.
You do not need a SIEM on day one. You need application logs that record authentication events, authorization failures, and admin actions — with timestamps and user identifiers, without passwords or tokens — retained somewhere for a few months. That baseline turns a future incident from pure guesswork into an investigation. It is also the raw material for everything you might build later.
What not to bother with yet
Honesty requires the other list. Things I see small teams buy or build too early: web application firewalls in front of unfixed code, threat modeling workshops that produce documents nobody revisits, bug bounty programs before basic hygiene exists, and security tooling whose alerts nobody is staffed to read. I made a version of this mistake myself — early on I over-invested in process documents when an afternoon of pipeline automation was worth more. Sequence matters. Habits first, tooling second, hires third.
When you do eventually need the hire
Scale changes the answer: compliance obligations, sensitive data at volume, a genuine attack surface. But teams that adopt the habits above hire from strength — the security person arrives to extend a working baseline, not to excavate years of scattered authorization logic and committed secrets.
The 20% is not a substitute for expertise forever. It is what makes expertise affordable when the time comes.
How Encryption Actually Protects — and Doesn't Protect — You →