Index Β· How it works
9 min read- How it works
- Secure design & threat modeling (A04 Insecure Design)
- Security misconfiguration (A05)
- Vulnerable & outdated components (A06)
- Software & data integrity failures (A08)
- Server-Side Request Forgery β SSRF (A10)
- The DevSecOps toolchain (and where each runs)
- Secure defaults & defense in depth
- Logging & monitoring (A09 β detect and respond)
How it works
A secure SDLC maps a set of security activities onto the phases every project already has β Design β Build/Code β Test β Deploy β Run/Operate β and automates as many of them as possible inside CI/CD. The OWASP Top 10 categories below are not "bugs to grep for"; several of them are whole classes of failure that are prevented by process, not by a single fix. The DevSecOps toolchain (SAST, DAST, IAST, SCA, secret scanning) is the automation layer that makes "shift left" real: checks run on every pull request and every build, so a developer gets feedback in minutes instead of a pentester finding it months later.
Secure design & threat modeling (A04 Insecure Design)
Insecure Design is the category for flaws that exist before a line of code is written β the architecture is missing a control, a trust boundary, or a security requirement. The hallmark of A04 is that you cannot fix it by patching code, because there's no buggy line to correct: the control was never required in the first place. Examples β a password-reset flow with no rate limit and a 4-digit code (brute-forceable by design), a "transfer funds" endpoint with no second-factor or limit, a workflow that trusts a client-supplied price. The fixes are design activities:
- Threat modeling β systematically asking "what can go wrong here?" against a data-flow diagram, identifying assets, trust boundaries, and attacker entry points.
- Abuse / misuse cases β for every user story ("as a user I can reset my password"), write the attacker's version ("as an attacker I brute-force the reset code") and design a control against it.
- Security requirements β capture non-functional security requirements (rate limits, authn/authz, encryption, audit) as first-class acceptance criteria, not afterthoughts.
- Secure design patterns & reference architectures β reuse vetted patterns (BFF, parameterized data access, central authz) rather than reinventing.
STRIDE is the most common threat-modeling mnemonic β it enumerates the six categories of threat against each element of the system:
STRIDE threat category β property it violates β example
S Spoofing β Authentication β forging another user's identity / token
T Tampering β Integrity β modifying data or code in transit / at rest
R Repudiation β Non-repudiation β denying an action; no audit trail to prove it
I Information disclosure β Confidentiality β leaking PII, secrets, internal errors
D Denial of service β Availability β exhausting resources / rate-unlimited endpoint
E Elevation of privilegeβ Authorization β a normal user gaining admin rights
Other useful frames: DREAD (a risk-rating scheme β Damage, Reproducibility, Exploitability, Affected users, Discoverability), PASTA (a risk-centric process), and attack trees. The point of any of them is to make the implicit explicit at design time.
Security misconfiguration (A05)
Misconfiguration is the gap between "the software can be secure" and "this deployment is secure." The code may be fine; the way it's stood up is not. Classic instances:
- Default credentials left in place (
admin/admin, the database's default superuser password, an unauthenticated admin console). - Verbose errors in production β stack traces, framework versions, SQL fragments, internal hostnames leaked to the client (information disclosure that feeds the next attack).
- Open cloud storage β public S3 buckets / blob containers, overly broad IAM, security groups open to
0.0.0.0/0. - Unnecessary features enabled β sample apps, debug endpoints, directory listing, unused ports/services,
TRACE/OPTIONS, an admin actuator exposed publicly. - Missing hardening & security headers β no
Content-Security-Policy,Strict-Transport-Security,X-Content-Type-Options,X-Frame-Options/frame-ancestors; permissive CORS (Access-Control-Allow-Origin: *with credentials). - Drift β a hardened baseline that erodes over time as people make "temporary" changes.
β Production app returning to the browser:
HTTP 500
System.Data.SqlClient.SqlException: Invalid column 'Passwrd' ...
at MyApp.Data.UserRepository.GetByEmail() in /src/Data/UserRepository.cs:line 42
Server: Kestrel X-Powered-By: ASP.NET (framework + path + schema leaked)
β
Production app returning:
HTTP 500
{ "error": "An unexpected error occurred", "traceId": "00-abc123..." }
(detail logged server-side under that traceId; nothing internal leaks)
Defenses: a hardened, repeatable baseline (CIS Benchmarks), configuration as code and immutable infrastructure (so prod matches a reviewed template), least-privilege everywhere, removing/disabling everything you don't use, and an automated config-audit / posture-management check in the pipeline. Secure defaults matter most here β the safe configuration should be what you get out of the box, with insecure options requiring an explicit, reviewed opt-in.
Vulnerable & outdated components (A06)
Modern apps are mostly other people's code β frameworks, libraries, base images, and their transitive dependencies. A06 is about shipping a component with a publicly known vulnerability (a CVE). You don't have to write the bug; you just have to depend on it. Log4Shell (CVE-2021-44228) is the canonical example: a logging library buried deep in transitive dependencies gave remote code execution to a huge swath of the internet.
- SCA (Software Composition Analysis) β tools (Dependabot,
npm audit,dotnet list package --vulnerable, Snyk, OWASP Dependency-Check, Trivy for images) that match your dependency tree against vulnerability databases (NVD, GitHub Advisory). - Transitive dependencies β the dependency you chose pulls in dozens you didn't. Most real-world component risk lives transitively, which is why a manual "review the libraries we import" misses it β you need the full resolved tree.
- SBOM (Software Bill of Materials) β a machine-readable inventory of every component and version in a build (SPDX or CycloneDX). When the next Log4Shell drops, an SBOM lets you answer "are we affected, and where?" in minutes instead of weeks.
- Patching cadence β a process to triage and apply security updates promptly; pin versions for reproducibility but have a path to upgrade. Remove unused dependencies (smaller attack surface).
- Provenance β prefer maintained, widely-used components; watch for abandoned packages and typosquats.
Software & data integrity failures (A08)
A08 is about trusting code, data, or updates without verifying their integrity β and it is the home of modern supply-chain attacks. The threat isn't a bug in your code; it's an attacker injecting malicious code into the things you build with or pull from.
- CI/CD pipeline integrity β your build system is now a high-value target. If an attacker can modify build scripts, inject a malicious step, or compromise a runner, they ship backdoored binaries signed with your name. The SolarWinds attack (2020) did exactly this: attackers compromised the build pipeline and inserted the SUNBURST backdoor into legitimately signed Orion updates, which then auto-deployed to ~18,000 customers. The lesson β protect, isolate, and audit the pipeline as a production system; least-privilege the build; require reviewed, signed changes to build config.
- Signed artifacts & provenance β sign build outputs (and verify signatures before deploy); generate provenance attestations (SLSA framework, Sigstore/cosign) so you can prove this binary came from that source via that pipeline.
- Unverified updates / auto-update β an update mechanism that fetches and runs code without verifying a signature is a remote-code-execution channel. Always verify a trusted signature before applying an update; pin update sources over TLS.
- Untrusted deserialization β deserializing attacker-controlled data into objects can execute code; treat serialized blobs as untrusted input, prefer safe formats, and validate.
- Locked / pinned dependencies β commit a lockfile (
package-lock.json,yarn.lock,Cargo.lock, NuGet lock files) and pin exact versions so a build is reproducible and a malicious new release of a transitive dep can't silently slip in. Use integrity hashes (Subresource Integrity for CDN scripts; lockfileintegrityfields) so a tampered artifact is rejected.
β Trusting unverified inputs / builds:
- "dependencies": { "left-pad": "latest" } β floats to whatever is newest, no lockfile
- <script src="https://cdn.example/lib.js"> β no integrity hash; CDN compromise = your XSS
- curl https://example/install.sh | sudo bash β runs unverified remote code as root
- build runner with push access to prod + no audit on pipeline changes
β
Verifying integrity end-to-end:
- exact pins + committed lockfile with integrity hashes
- <script src="..." integrity="sha384-..." crossorigin="anonymous">
- download, verify GPG/cosign signature, THEN run
- signed artifacts + SLSA provenance; least-privilege, audited CI/CD
Server-Side Request Forgery β SSRF (A10)
SSRF is when an attacker tricks your server into making an HTTP (or other-protocol) request to a destination the attacker chooses. The classic vector: a feature that fetches a user-supplied URL β "import from URL," a webhook, an image-from-link, a PDF renderer, an SSO metadata fetch. The danger is that your server sits inside the network, so it can reach things the attacker cannot: internal admin panels, databases, and especially the cloud metadata endpoint.
The cloud instance metadata service lives at the link-local address 169.254.169.254 and, on misconfigured instances, hands out temporary IAM credentials, user-data, and secrets to anything that asks from the host. An SSRF that reaches it can exfiltrate cloud credentials β this was the core of the 2019 Capital One breach.
SSRF block / allow strategy for any server-side fetch
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BLOCK these destinations (deny-list β necessary but not sufficient):
169.254.169.254 β cloud metadata (AWS/GCP/Azure IMDS)
169.254.0.0/16 β all link-local
127.0.0.0/8 ::1 β loopback
10.0.0.0/8 β private
172.16.0.0/12 β private
192.168.0.0/16 β private
0.0.0.0 fd00::/8 β unspecified / unique-local
file:// gopher:// dict:// β non-HTTP schemes
β
PREFER an ALLOW-LIST (the real fix):
- restrict outbound to an explicit set of allowed hosts/domains
- allow only http/https schemes; reject redirects to new hosts
- resolve DNS, validate the *resolved IP* against the deny ranges,
then connect to that IP (defeats DNS-rebinding / TOCTOU)
- enforce at the network layer too: egress firewall / no route to metadata,
and require IMDSv2 (token-bound) so a bare GET can't lift credentials
Why an allow-list beats a deny-list: attackers bypass naive deny-lists with alternate IP encodings (0x A9FE A9FE, decimal 2852039166), DNS that resolves to an internal IP, open redirects, and IPv6 forms. Validate the resolved IP (not just the hostname string), forbid following cross-host redirects, and add a network egress control as defense in depth.
The DevSecOps toolchain (and where each runs)
"Shift left" means moving security feedback as early as possible β ideally into the developer's editor and the pull request β because a flaw is cheapest to fix the moment it's introduced and most expensive once it's in production. The automation layer:
Tool What it analyzes When / where in the pipeline
ββββββββββββββ βββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββ
SAST source code / bytecode, statically IDE + PR + CI (early, "white box")
(no execution) β finds injection,
hardcoded secrets, unsafe APIs
SCA your dependency tree vs CVE DBs PR + CI + continuously (Dependabot)
+ license compliance + SBOM
Secret scanning git history & diffs for tokens/keys pre-commit hook + PR + CI
DAST the running app from outside, by staging / pre-prod (late, "black box")
sending real requests β finds runtime
issues SAST can't see (config, auth)
IAST instruments the running app from integration / QA test runs
inside (agent) β correlates a request
to the exact vulnerable line
- SAST (Static): no false sense of runtime context, but sees all code paths and runs early; tends to produce false positives. White-box.
- DAST (Dynamic): tests the real deployed behavior including configuration and auth flows, low false positives, but only covers what it can reach and runs late. Black-box.
- IAST combines the two β an in-process agent watches real traffic and sees the code, giving precise, low-false-positive findings tied to a line of code.
- SCA and secret scanning are the cheap, high-value gates everyone should have first.
The full picture: pre-commit secret scan β PR triggers SAST + SCA β build produces a signed artifact + SBOM β DAST/IAST against staging β policy gate (fail the build on high-severity findings) β deploy β continuous runtime monitoring.
Secure defaults & defense in depth
Two cross-cutting principles tie the whole lifecycle together. Secure by default means the out-of-the-box configuration is the safe one: deny by default, encryption on, the admin console bound to localhost, the dangerous flag off β so a developer who does nothing special still ends up secure, and insecurity requires a deliberate, reviewable choice. Defense in depth means layering independent controls so no single failure is fatal: parameterized queries and a least-privilege DB account and a WAF; SSRF allow-listing and an egress firewall and IMDSv2. The goal is fail-safe behavior β when a control is missed or breaks, the system fails closed, and the next layer contains the blast radius. Related principles: least privilege, separation of duties, minimizing attack surface, and complete mediation (check every access, every time).
Logging & monitoring (A09 β detect and respond)
No prevention is perfect, so you must be able to see an attack and react. A09 Security Logging & Monitoring Failures is the category for not having enough visibility: auth events, access-control failures, and high-value actions aren't logged; logs lack enough context (who/what/when/where); they aren't centralized, alerted on, or retained; and there's no incident-response plan. Build it in: log security-relevant events (logins, failures, privilege changes, admin actions) with correlation IDs but never secrets/PII in plaintext; ship logs to a tamper-resistant central store (SIEM); alert on anomalies (credential stuffing, spikes in 403s, SSRF-shaped egress); and rehearse response. Detection-and-response is the safety net under all the preventive controls above.