JTSTech Services
All articles

Security · May 15, 2026 · 7 min read

Security belongs in the foundation, not a patch

Retrofitting security onto a live application is expensive, incomplete, and sometimes impossible. The decisions that matter most happen in the first weeks of a project, not after something breaks.

Security gets treated like an audit. Something you schedule after the product is built, when there is time, when the budget allows. A checklist you run through before launch and update once a year. This framing produces systems that are technically compliant and genuinely vulnerable at the same time.

The most exploitable bugs in production software are not exotic zero-days. They are decisions made early in development that were never meant to be security decisions: how data is stored, how sessions are managed, how inputs are validated, which third-party libraries were pulled in without review. By the time an audit finds them, they are woven into the architecture.

The early decisions that determine your attack surface

Authentication is the first place most applications leak. Not through sophisticated brute-force attacks, but through lazy defaults: no rate limiting on login endpoints, no account lockout, passwords stored with outdated hashing algorithms, session tokens that never expire. These are not hard problems. They are solved problems. But they require intentional choices at the start of a project, not patches later.

  • Use a dedicated authentication library or service rather than rolling your own token logic
  • Enforce MFA for any admin or privileged role from day one
  • Rate limit login, registration, and password reset endpoints before launch
  • Set token expiry and implement refresh token rotation
  • Never store passwords in plaintext — use bcrypt or Argon2 with appropriate cost factors

Data access control is the other early failure point. Applications that start with a simple data model often bolt on multi-tenancy or role-based access later. When access control is an afterthought, it tends to be inconsistent — enforced in some API routes and missing in others, visible in the UI but bypassable at the API layer. The correct approach is defining your authorisation model before you write your first data query.

Dependencies are not your code, but they are your problem

A modern web application pulls in hundreds of open-source packages. Each one is a potential attack vector. This is not a reason to avoid open-source dependencies — it is a reason to manage them deliberately. Know what you are pulling in, keep dependencies current, and have an automated process that flags vulnerabilities before a human has to notice them.

  • Run dependency audits in CI — not just locally, not just before deployment
  • Subscribe to security advisories for the frameworks and databases you use
  • Remove unused dependencies; every package you do not need is one you do not have to patch
  • Pin dependency versions in production and review updates before upgrading
  • Assess third-party scripts loaded in the browser with the same scrutiny as server dependencies
Every dependency you add is a trust relationship. Treat it like one.

Infrastructure security is not the ops team's problem alone

Cloud infrastructure defaults are not designed for security. They are designed for accessibility — so that developers can get started quickly. Default-open storage buckets, overpermissioned service accounts, unencrypted environment variables, no network segmentation: these are common, they are preventable, and they are the category of incident that generates the most embarrassing breach announcements.

The principle of least privilege applies everywhere. A service that reads from a database should not have write permissions. A deployment pipeline that needs to push containers should not have access to production secrets. These boundaries are easy to set early and painful to enforce after permissions have already propagated through a running system.

What secure-by-default actually looks like

Secure-by-default does not mean paranoid. It means building applications where the path of least resistance for a developer is also the secure path. Input validation built into the data layer, not left to individual controller logic. Secret management through a dedicated vault, not copy-pasted into environment files. Infrastructure-as-code that enforces network policy rather than relying on humans to remember the rules.

The goal is a system where security does not depend on every developer remembering every rule every time. That is not a realistic standard. Build the guardrails into the platform and let developers move fast inside them. That is how you get speed and security in the same codebase.

Keep reading

Have a project for us?

Let's build something that works — across the whole stack.

Tell us what you're building — we'll get back to you fast.