Warmup Guide — Product Security as an Engineering Control System

Zero-to-expert primer for Phase 03. It builds, from first principles, the discipline that turns security from a pile of late findings into repeatable engineering controls: threat modeling (STRIDE, DFDs, trust boundaries, attack trees), the strengths and limits of each scanner class (SAST/DAST/IAST/SCA/secret/IaC/container), supply-chain integrity (SBOM, SLSA, provenance, signing with Sigstore), CI/CD hardening, vulnerability management as a workflow, and executive risk communication. Assumes you've done Phase 02. By the end you should be able to threat-model a feature, design a release gate that fails on real risk and stays green otherwise, and explain a security investment to a VP in one page.

Table of Contents


Chapter 1: Why Shift Left — Cost and the Control System View

Zero background. "Shifting left" means moving security activity earlier in the software lifecycle — from "pen-test the finished product" toward "design securely, catch issues in code review and CI." The justification is economic: the cost to fix a flaw rises sharply the later it is found. A bad trust-boundary decision caught in a design review costs a conversation; the same flaw caught after launch costs a redesign, a migration, an incident, and possibly a breach.

The control-system framing — the mental model for the whole phase. Don't think of AppSec as "finding bugs." Think of it as designing a control system around the software delivery pipeline:

design → code → build → test → release → run
  ↑ threat model   ↑ review/SAST   ↑ provenance/sign   ↑ DAST   ↑ gate   ↑ detection

Each stage gets controls that are repeatable (run every time, not heroically), owned (someone is accountable), and verifiable (you can prove they ran and what they found). A control that depends on a specific person remembering is not a control.

Why this is a staff-level skill. Anyone can run a scanner. The differentiator is building a program — controls that scale across hundreds of engineers without making the security team the delivery bottleneck. That tension (security vs. velocity) is the central design problem, and the answer is paved roads: secure defaults so easy to use that the secure path is the easy path.

Misconception to kill now. "More scanning = more security." Untuned scanning produces noise, trains developers to ignore alerts, and blocks builds on false positives. A program is measured by outcomes (real risk reduced, recurrence prevented), not scan volume.

Chapter 2: Threat Modeling from First Principles

What it is. Threat modeling is structured anticipation: before (or alongside) building a system, you reason about what could go wrong, so you can design defenses in rather than bolt them on. Four questions, due to Adam Shostack, frame the whole exercise:

  1. What are we building? (a model — usually a data-flow diagram)
  2. What can go wrong? (threats — enumerated with a method like STRIDE)
  3. What are we going to do about it? (mitigations)
  4. Did we do a good job? (validation)

Why a model, not the real system. You can't reason about every detail at once. A threat model is a deliberate abstraction that surfaces trust boundaries and data flows — exactly the places attacks happen — while hiding irrelevant detail.

The output is decisions, not a document. A threat model that doesn't change a design decision, add a mitigation, or accept a risk explicitly was theater. The deliverable is: assets, actors, trust boundaries, a prioritized list of threats connected to concrete mitigations, and a residual-risk register.

Misconception to kill now. "Threat modeling is filling out a STRIDE checklist." Checklist-only threat modeling is the #1 failure mode (the README flags it). STRIDE is a prompt to think, not a form to complete — the value is in the reasoning about your data flows and boundaries.

Chapter 3: STRIDE, DFDs, and Trust Boundaries

Data-Flow Diagrams (DFDs). A DFD models a system as: external entities (users, third parties), processes (your services), data stores (databases, buckets), and data flows (arrows between them). You then draw trust boundaries — lines where the level of trust changes (internet↔your edge, app↔database, tenant A↔tenant B, your code↔a third-party API). Threats concentrate on the arrows that cross trust boundaries, because that's where untrusted meets trusted.

STRIDE — a mnemonic for threat categories, each the violation of one security property:

STRIDEThreatProperty violatedTypical mitigation
Spoofingpretending to be someone elseAuthenticationstrong authN, mTLS, signed tokens
Tamperingunauthorized modificationIntegritysignatures, checksums, access control
Repudiationdenying an actionNon-repudiationaudit logs, signed records
Information disclosureleaking dataConfidentialityencryption, authZ, minimization
Denial of servicemaking it unavailableAvailabilityrate limits, quotas, isolation
Elevation of privilegegaining more rightsAuthorizationleast privilege, authZ checks

How to apply it. For each element/flow that crosses a boundary, walk the six letters and ask "can this happen here?" A flow from the internet to your API invites Spoofing (who's calling?), Tampering (can they alter it in transit?), and DoS (can they flood it?). This per-element sweep is what turns STRIDE from a checklist into analysis.

Production significance. The threat-model and threat-model-validator labs make you produce and machine-check this artifact: every threat must connect an asset, actor, boundary, precondition, and mitigation — a model with dangling threats or unmitigated high-severity items fails validation.

Chapter 4: Attack Trees and Abuse Cases

Attack trees model an attacker's goal as the root, with refinements (AND/OR sub-goals) as branches — a structured way to enumerate paths to a goal and find the cheapest one. Root: "read another tenant's data." Children (OR): "exploit IDOR", "steal a token", "abuse an export job", "compromise the DB credential". Each leaf is a concrete thing to defend. Attack trees complement STRIDE: STRIDE enumerates threat types per element; attack trees enumerate paths to a specific goal.

Abuse / misuse cases are the dark mirror of use cases. A use case: "user uploads a profile photo." An abuse case: "attacker uploads a 10 GB file / a polyglot file / a path-traversal filename / a malware sample." (A polyglot file is crafted to be simultaneously valid as two formats — e.g. bytes that are both a valid image and valid JavaScript — so it passes a type check as one thing and is later executed as the other; a classic upload-filter bypass.) Writing 20 abuse cases for a feature (the lab requirement) forces you to think like the adversary about every input and state transition, which surfaces threats a happy-path design misses.

Misconception to kill now. "We listed the threats, we're done." A threat list without prioritization (which paths are cheap and high-impact?) gives no guidance on what to fix first. Attack trees help you rank by attacker cost vs. defender value.

Chapter 5: Secure Design Review vs Code Review

These are different altitudes and you must not conflate them:

  • Secure design review asks: is the architecture sound? Are trust boundaries in the right places? Is authorization centralized and correct? Is the data model multi-tenant-safe? Are secrets managed well? Design flaws are expensive because they're structural — no amount of clean code fixes a missing trust boundary.
  • Secure code review asks: does the implementation match the secure design and avoid implementation defects (injection, missing authZ check, unsafe deserialization)?

Why separate them. A perfect implementation of an insecure design is insecure; a secure design with a buggy implementation is also insecure. You need both reviews, and you must label findings as design vs implementation because they route to different fixes (re-architecture vs. a patch) and different owners. The design-review lab produces Architecture Decision Records (ADRs) — durable records of why a security-relevant decision was made — and a residual-risk register of what you consciously chose not to fully mitigate.

Misconception to kill now. "SAST covers code review." SAST finds patterns; it cannot judge whether your authorization model is correct or whether a trust boundary is missing (Chapter 6). Human review owns the judgment calls.

Chapter 6: The Scanner Zoo — What Each Tool Can and Cannot See

Each tool sees the program through a different window. Knowing the blind spots is what separates a security engineer from a button-pusher:

  • SAST (Static Application Security Testing) — analyzes source/bytecode without running it. Sees data flow from sources to sinks; great for injection patterns. Blind to runtime config, real authorization logic, and anything requiring execution; prone to false positives on unreachable paths. (Semgrep, CodeQL.)
  • DAST (Dynamic) — pokes the running app from outside like an attacker. Finds real, reachable issues and config problems; blind to code it can't reach and to root cause. (OWASP ZAP.)
  • IAST (Interactive) — instruments the running app to watch data flow during tests. Combines some SAST precision with DAST's reachability, but needs good test coverage to exercise paths.
  • SCA (Software Composition Analysis) — inventories third-party dependencies and flags known CVEs. Essential, but the raw output is enormous and mostly not reachable — which is why reachability/exploitability filtering (Chapter 10) is the real skill. (Trivy, Grype.)
  • Secret scanning — finds committed credentials. High value, but a hit means rotate the secret, not just delete the line (it's in git history).
  • IaC scanning — checks Terraform/Kubernetes/CloudFormation for insecure configuration (public bucket, open security group). (Checkov, Conftest/OPA.)
  • Container scanning — known CVEs in base images and layers. (Trivy.)

The unifying lesson: every scanner has false positives (noise that erodes trust) and false negatives (missed real bugs). A program tunes tools — suppressions with owner and expiry, not permanent silence — and measures precision/recall against a labeled corpus.

Misconception to kill now. "Green pipeline = secure." Tools cover the classes they're built for; design flaws, business-logic abuse, and authorization gaps slip through every one of them.

Chapter 7: Where Each Check Belongs — Pre-commit to Runtime

Controls have a right place in the pipeline, chosen by speed and signal:

  • Pre-commit / IDE: fast, local checks — linters, secret detection, format. Must be near-instant or developers disable them.
  • CI (per PR): SAST, SCA, secret, IaC, container scans, unit/integration security tests. Fast enough to gate a merge; this is the workhorse stage.
  • Pre-deploy / release gate: DAST against a deployed build, SBOM generation, artifact signing and provenance verification (Chapter 8), policy checks. This is the last gate before production.
  • Runtime: detection, WAF (web application firewall — edge request filtering), anomaly monitoring, drift detection — for what static analysis can't predict.

The design principle: put each check at the earliest stage where it has enough signal to be accurate, and make slow/noisy checks asynchronous so they don't block fast feedback. The security-release-gate lab encodes exactly this: a gate that blocks on seeded critical cases and passes approved fixtures, with an auditable emergency-exception path.

Chapter 8: Supply-Chain Security — SBOM, SLSA, Provenance, Signing

Why this is now central. Modern software is mostly other people's code assembled by automated pipelines. Attackers learned to compromise the supply chain (a dependency, a build server, a package registry) rather than the app — SolarWinds, the event-stream/xz backdoors, dependency-confusion attacks (tricking a build into pulling a malicious public package in place of an intended private one, usually by publishing a higher version number under the same name). The supply chain is itself a system to secure.

The four pillars, from first principles:

  • SBOM (Software Bill of Materials). A machine-readable inventory of everything in your build — direct and transitive dependencies, versions, licenses. Standard formats: CycloneDX and SPDX. Generated by tools like Syft. Why: when the next critical CVE drops, "are we affected, and where?" must be answerable in minutes, not a frantic audit.
  • Provenance. Verifiable metadata about how an artifact was built — which source commit, which builder, which inputs. It answers "did this binary actually come from this source via our trusted pipeline?" (The in-toto attestation format.)
  • SLSA (Supply-chain Levels for Software Artifacts). A graded framework (levels of increasing rigor) for build integrity: source/build provenance, isolated/hermetic builds, two-person review. It gives you a target maturity to design toward.
  • Signing (Sigstore / Cosign). Cryptographically sign artifacts so consumers can verify origin and integrity. Sigstore makes this keyless using short-lived certificates tied to an identity.

The crucial verb is verify. Signing without verification at the consumption point is theater — the README explicitly calls out "unsigned-but-unverified artifacts" as a common mistake. The provenance-verifier lab makes you verify an SBOM + provenance + signature and detect three tampering classes: a modified artifact, a forged source reference, and a wrong builder identity.

Misconception to kill now. "We sign our releases, so we're covered." If nothing checks the signature before deploy, the signature changes nothing. The control is verification, with signing as its prerequisite.

Chapter 9: Hardening the CI/CD Pipeline Itself

The insight: the pipeline is production infrastructure with write access to production. A compromised CI runner can sign and ship a backdoor with all your provenance intact, because it is the trusted builder. So the pipeline must be threat-modeled like any high-value system:

  • Permissions and tokens. CI tokens are frequently over-scoped (write to all repos, deploy to prod). Use least-privilege, short-lived, OIDC-federated credentials instead of long-lived stored secrets; scope per-job.
  • Runners. Shared/self-hosted runners can be poisoned by one job and persist to the next; prefer ephemeral, isolated runners.
  • Caches and dependencies. A poisoned cache or a dependency-confusion package injects code into every build; pin and verify dependencies, lock files, and use trusted registries.
  • Separation of duties. The identity that builds should not be the only identity that approves release; emergency paths must be auditable.

Misconception to kill now. "The pipeline is just automation, not an attack surface." The pipeline is the most valuable target — it holds the keys to ship trusted code to every user.

Chapter 10: Vulnerability Management as a Workflow

The problem of scale. A real program generates thousands of findings. Triaging by raw count is hopeless and the wrong target. Vulnerability management is a workflow with explicit states:

intake → deduplicate → assess (reachability, exploitability, asset criticality)
       → prioritize (severity + business context) → assign (owner + SLA)
       → remediate / accept-with-exception → retest → close → measure recurrence

The judgment that matters most: reachability and exploitability. Of 10,000 dependency findings, most are in code paths you never call or require conditions you don't meet. The skill is filtering to the few that are actually reachable and exploitable in your context (does the vulnerable function get called? with attacker-controlled input? across a trust boundary?). This is why "how do you prioritize 10,000 dependency findings?" is a standard interview question — the wrong answer is "fix them all," the right answer is "rank by reachability × exploitability × asset criticality, fix the reachable-critical few now, batch the rest."

Recurrence prevention. Every accepted critical/high finding gets a regression test so it can't silently return — the same fix-plus-regression discipline as Phase 01, applied at program scale.

Misconception to kill now. "Severity = CVSS base score." CVSS base score ignores your context. A 9.8 in an unreachable path may be lower real risk than a 6.5 on your auth boundary. Combine the base score with reachability and asset criticality.

Chapter 11: Risk Rating, Exceptions, and Executive Communication

Risk, defined. Risk ≈ likelihood × impact, contextualized by asset criticality and existing compensating controls. Your job is to translate technical findings into business risk a decision-maker can act on.

A defensible exception process. Not everything can be fixed now. A real program lets teams accept risk — but only through an auditable process: a named owner, a stated business justification, compensating controls, and a hard expiry date (so "temporary" exceptions don't become permanent). Suppressions and exceptions without expiry are a top failure mode.

Executive communication — the one-page memo. Executives don't fund "we have 4,000 highs." They fund decisions. A good security memo is one page: the risk (in business terms), the options (with trade-offs), a clear recommendation, the investment required, the owner, and the success metric. Raw scanner totals are noise; exposure and control health are signal.

Persuading a VP to fund a platform fix. Frame it as leverage: a paved-road fix (e.g. a shared, correct authorization library) eliminates a class of bugs across every team forever, versus paying for the same bug repeatedly in pen-tests and incidents. Tie it to a metric they own (velocity, incident cost, audit findings).

Misconception to kill now. "Security's job is to say no." A security program that only blocks becomes the bottleneck everyone routes around. The job is to make the secure path the easy path and to present decisions, not vetoes.

Lab Walkthrough Guidance

The runnable labs encode the program's enforcement points:

  1. Lab 02 — Threat Model Validator. Start here conceptually: produce a threat model (Chapters 2–4) and make it machine-checkable — every threat connects asset, actor, boundary, precondition, and mitigation; dangling or unmitigated high-severity threats fail.
  2. Lab 03 — Artifact Provenance Verifier. Build verification of SBOM + provenance + signature (Chapter 8) and prove it detects a tampered artifact, a forged source reference, and a wrong builder identity.
  3. Lab 01 — Security Release Gate. Tie it together: a release gate (Chapter 7/11) that blocks on seeded critical cases, stays green on approved fixtures, and exposes an auditable emergency-exception path with expiry.
  4. Lab 04 — SAST Taint-Analysis Engine. Track taint from sources through sanitizers to sinks — what SAST actually does under the hood (Chapter 6), and where its false positives/negatives come from.
  5. Lab 05 — Secret Detection. Catch committed secrets via high-confidence patterns and Shannon entropy with placeholder/allowlist suppression (the gitleaks model, Chapter 6) — a hit means rotate.

Run each against your implementation and the reference:

pytest test_lab.py -v
LAB_MODULE=solution pytest test_lab.py -v

Success Criteria

You are ready for Phase 04 when you can, without notes:

  1. Threat-model a feature using DFDs, trust boundaries, and STRIDE, ending in mitigations — not a filled-out checklist.
  2. Separate design findings from implementation defects and route each correctly.
  3. State what SAST, DAST, IAST, SCA, secret, IaC, and container scanning each cannot see.
  4. Place each check at the right pipeline stage and justify why.
  5. Explain SBOM, provenance, SLSA, and signing — and why verification is the actual control.
  6. Threat-model the CI/CD pipeline itself and name three concrete hardening controls.
  7. Prioritize 10,000 dependency findings by reachability × exploitability × criticality.
  8. Write a one-page executive memo that presents a decision, not scanner totals.

Common Mistakes

  • Checklist-only threat modeling that changes no decision.
  • Blocking builds on untuned tools; training developers to ignore alerts.
  • Vanity metrics (vulnerability counts) instead of exposure and control health.
  • Permanent suppressions/exceptions with no owner or expiry.
  • Signing artifacts but never verifying them before deploy.
  • Treating the CI pipeline as automation rather than a high-value attack surface.
  • A central security team that becomes the delivery bottleneck instead of building paved roads.

Interview Q&A

Q: Threat-model a multi-tenant SaaS export feature. A: Model it as a DFD: user → export service → datastore → object storage → download link, with trust boundaries at internet↔edge, tenant↔tenant, and app↔storage. Walk STRIDE per crossing: Spoofing (authN on the request), Tampering (signed/expiring download URLs), Info disclosure (the export must enforce object-level authZ per row, not just at request start — and must not leak across tenants in a shared job), DoS (rate/size limits on exports), Elevation (the background job must run with the requesting user's authority, not a superuser). Top threats: cross-tenant data in a shared export job and a long-lived public download link. Mitigations: per-row authZ in the job, short-lived signed URLs, per-tenant isolation, size/rate quotas.

Q: Which security checks belong pre-commit, in CI, at deploy, and at runtime? A: Pre-commit: fast local linting and secret detection. CI per-PR: SAST, SCA, secret, IaC, container scans, security unit tests. Deploy/release gate: DAST on the built app, SBOM generation, signing and provenance verification, policy checks. Runtime: detection, WAF, anomaly and drift monitoring. The rule is earliest stage with enough signal to be accurate; slow/noisy checks run async so they don't block fast feedback.

Q: How do you prioritize 10,000 dependency findings? A: Not by count. Deduplicate, then rank by reachability (is the vulnerable function actually called with attacker-controlled input across a trust boundary?), exploitability, and asset criticality. Fix the reachable-and-critical few immediately, batch the rest into normal upgrade hygiene, and record exceptions with owner and expiry. SBOM makes "are we affected and where" answerable; reachability analysis cuts the 10,000 to the handful that matter.

Q: Design a defensible exception process. A: Every exception needs a named owner, a business justification, documented compensating controls, and a hard expiry date, recorded in an auditable system. At expiry it must be re-reviewed, not auto-renewed. This lets teams move fast without "temporary" risk acceptances becoming permanent blind spots.

Q: How would you persuade a product VP to fund a platform-level fix? A: Frame it as leverage and cost avoidance: a paved-road fix (a shared correct authZ library, a hardened service template) removes a bug class across every team permanently, versus paying for the same finding repeatedly in pen-tests, incidents, and audit findings. I'd tie it to a metric the VP owns — delivery velocity, incident cost, or audit exposure — and present it as a one-page decision with options, recommendation, investment, and success metric.

References

Frameworks and standards

  • OWASP SAMM (Software Assurance Maturity Model); OWASP ASVS (verification standard).
  • NIST SP 800-218 SSDF (Secure Software Development Framework).
  • SLSA specification (slsa.dev); in-toto attestation framework.
  • CycloneDX and SPDX SBOM specifications; OpenSSF Scorecard.

Threat modeling

  • Adam Shostack, Threat Modeling: Designing for Security.
  • Microsoft STRIDE methodology; OWASP Threat Modeling Cheat Sheet.

Supply chain

  • Sigstore / Cosign documentation; SolarWinds, event-stream, and xz (CVE-2024-3094) postmortems.
  • "Dependency Confusion" (Alex Birsan) — substitution-attack writeup.

Tooling

  • Semgrep, CodeQL, OWASP ZAP, Trivy, Syft, Checkov, OPA/Conftest documentation.