The worst time to think about security is the week before launch, which is when most teams think about it. A penetration test in the final sprint finds problems that cost ten times more to fix than they would have cost to prevent, and the fixes ship under deadline pressure, which is how fixes create new problems.
Security by design means the boring controls are present from sprint one, enforced by tooling rather than memory. Here is what that looks like on our projects, and why each piece earns its place.
Threat model at the whiteboard, not the audit
Every project gets a one-hour threat modeling session before the first sprint. No framework ceremony, just four questions asked about the system diagram: what are we building, what can go wrong, what are we doing about it, and did we miss anything. The output is a short list of concrete risks ranked by likelihood and damage, and it drives real decisions.
On a lending platform, that hour surfaced the risk that mattered most: an attacker enumerating ID numbers through the application status endpoint. The fix, opaque application references instead of sequential IDs, cost twenty minutes in week one. Found at audit time, it would have meant reworking URLs, emails, and the SMS templates a partner had already integrated.
Least privilege everywhere, enforced by default
- Application accounts get the narrowest database grants that work. The web app cannot drop tables. The reporting service is read-only.
- Cloud roles are scoped per service. The upload service can write to one bucket, not the account.
- People get access through short-lived, logged sessions instead of standing admin rights. Production database access is the exception, requested and expiring, never the default.
- New permissions start denied. Every access rule is an explicit allow, so a forgotten check fails closed instead of open.
Least privilege is not about distrusting your team. It is about limiting the blast radius of the credential that eventually leaks. When a contractor laptop is stolen or a dependency exfiltrates an environment file, scoped credentials turn a breach into an incident report.
Secrets and dependencies: the two quiet doors
Most real-world breaches walk through one of two doors: a leaked secret or a vulnerable dependency. Both are closed with tooling, not vigilance. Secrets live in a managed vault, never in code or chat, and every repository runs a pre-commit scanner that blocks the commit the moment a key touches a diff. Dependencies get automated vulnerability scanning in CI, with critical findings failing the build, and a monthly update cadence so upgrades stay small.
POPIA is a design constraint, not a policy document
For South African products, POPIA compliance is decided in the schema, not the privacy policy. Collect only the fields the product needs, tag personal information at the column level, and build retention and deletion as scheduled jobs from day one. Retrofitting a "delete this person" capability into a system with personal data denormalised across 30 tables is a project. Designing it in is a sprint task.
For clients in financial services, we extend this with immutable audit logs and field-level encryption for the columns that would hurt most in a breach.
What this costs, honestly
~5%
of sprint capacity spent on built-in security practices
10x
typical cost multiple of fixing a design flaw found at audit
1 hour
threat modeling session that sets up the whole project
Security by design costs a few percent of every sprint. Security by audit costs a bad month right before launch, and sometimes a headline after it. Every project we deliver ships with the practices above as standard, not as a premium tier. If you want to know how they fit into our delivery process end to end, how we work walks through it.
