10 April 2024 Security By Vedhagiri Prakasam

How We Embed Security into Every Line of Code

Security added at the end of a project is not security. It is a report about how insecure the project already is.

The traditional shape of a secure project is a penetration test a fortnight before launch. Findings arrive when the architecture is settled, the deadline is fixed and nobody has the appetite to change anything structural. So the deep findings get accepted as risk and the shallow ones get patched.

This is not a failure of diligence. It is a failure of sequencing. A design flaw found on the day it is designed costs a conversation; the same flaw found after launch costs a migration. The fix is to move the finding earlier, not to test harder at the end.

Security checks running as part of a development pipeline

Security throughout the lifecycle

Threat modelling before the first line of code

Before implementation we work through four questions with the people who understand the domain: what are we building, what can go wrong, what are we going to do about it, and did we do a good enough job. It does not require a formal methodology to be useful. A whiteboard, a data-flow sketch and an hour with the engineers and somebody from the business will surface most of what matters.

What it produces that a late penetration test cannot is a record of the risks that were considered and consciously accepted. The dangerous vulnerabilities are rarely the ones somebody weighed and accepted; they are the ones nobody thought about at all.

Reviewing an application's data flows and trust boundaries
Automated security checks reporting on a pull request

What runs automatically, and where

Automation is for the classes of problem a machine finds reliably and a human finds tedious. Each check runs at the point where it is cheapest to act on.

Static analysis, on every pull request

SAST reads source code for injection paths, unsafe deserialisation, path traversal and similar recognisable patterns. Its weakness is false positives, and the failure mode is social rather than technical: a tool that cries wolf gets ignored, then disabled. Tuning the ruleset until findings are believable matters more than enabling every rule available.

Dependency and supply-chain scanning

Most code in a modern application was written by somebody else. SCA tooling compares the dependency tree against known-vulnerability databases, and generating a software bill of materials means that when the next widely-exploited library issue lands, answering "are we affected?" takes minutes rather than a week of grepping. Transitive dependencies are where this earns its keep — the risky package is usually one nobody chose directly.

Secret scanning

Credentials committed to a repository are among the most reliably exploited weaknesses in real breaches, because they need no exploitation at all. Scanning runs pre-commit and in CI, and the important half of the response is the part people skip: a secret that reached version control must be rotated, not merely deleted. Git history keeps it, and so does every clone taken before the deletion.

Dynamic testing against a running build

DAST exercises the deployed application and catches what source analysis cannot see — misconfigured headers, authentication and session handling, and the behaviour of the stack as assembled rather than as written.

Secrets belong in a manager, not in a file

Configuration separates from code, secrets are injected at runtime from a managed store, and no credential is written into a client bundle — anything shipped to a browser is public by definition, regardless of how it is obfuscated. Where a third-party API must be called with a key, the call belongs behind a server-side endpoint that holds the key and enforces its own rate limiting, so the credential is never distributed to users at all.

This is the discipline that most often slips, and it slips on real projects under real deadlines rather than in principle. Treating secret hygiene as something to be audited and corrected periodically, rather than assumed, is the honest position.

What automation will not find

No scanner finds broken access control, which is consistently among the most prevalent classes of web application weakness and is almost entirely a logic problem. Whether a user should be able to read a given record is a question about the domain, not about the code, and a tool has no way to know the intended answer. The same applies to business-logic flaws: a workflow that lets a discount be applied twice is functioning exactly as written.

These are found by people who understand the system, in code review and design discussion. Automation exists to clear the mechanical findings out of the way so that review attention is available for the problems that need judgement.

After deployment

Security headers and transport configuration are verified on the live site rather than assumed from the repository, because they are set by server configuration that no build artefact controls. Dependency scanning continues after release — a library safe on launch day becomes vulnerable when somebody publishes an advisory, with no change on our side. Logging is built so that answering "what happened, and to which records" is possible after an incident, which is a decision that has to be made before one.

The honest summary

None of this makes software secure, and any vendor claiming otherwise is selling something. It makes the common failures unlikely, the uncommon ones visible sooner, and the response to a disclosure a process rather than an emergency. That is a realistic goal, and unlike "secure" it can actually be checked.

Muscat Tech Solutions builds software for banks, government bodies and enterprises across Oman and the GCC, where this way of working is a requirement rather than a preference. Talk to us about your project.

You may also like

Related posts