Offensive Security for DevSecOps
A pipeline can run SAST, DAST, and SCA on every single commit, block the merge on any finding above a severity threshold, and still ship an application a human attacker walks straight through — not by exploiting a bug the scanners missed, but by using the application exactly as it was built to be used, in an order nobody anticipated. This page is about the layer of security testing that starts where automated scanning structurally ends: penetration testing, red teaming, and purple teaming. By the end you should be able to state precisely what a human tester finds that a scanner cannot and why, choose the right engagement type for a given goal, and explain how a well-run purple-team exercise changes a detection stack on the same day it runs — instead of producing a PDF that gets filed and re-read three months later during the next audit.
A metal detector at the airport is very good at one specific job: finding metal. It will catch a pocketknife every single time. It will never catch someone who talks their way past the guard by pretending to be an airline employee, because that person is carrying nothing metal at all — they're breaking a rule the detector was never built to check. SAST, DAST, and SCA are the metal detector: fast, tireless, and excellent at the specific shapes of bug they're built to recognize. A penetration tester is the person whose entire job is to try the "talk your way past the guard" move — and a red team is the person who does it quietly enough that nobody even realizes someone got through until they check the tapes afterward.
Where automated scanning stops: the structural blind spot
☺ Like you're 10: A spell-checker can tell you "recieve" is spelled wrong. It cannot tell you that the sentence it's sitting in is a lie. Scanners check spelling; they don't check whether the story makes sense.
It's worth being precise about the word "structural" here, because it's doing real work. SAST, DAST, and SCA aren't bad at finding bugs — they're extraordinarily good at finding a specific, well-defined category of bug, fast, on every commit, without getting tired or skipping the boring parts a human tester might rush through at 5pm on a Friday. What they cannot do isn't a maturity gap that a better rule set eventually closes. It's a category mismatch between what each tool is built to reason about and what a business-logic flaw actually is:
- SAST reads source code without executing it, so it reasons about a function's internals — an unsanitized string reaching a query, a hardcoded secret, a missing bounds check. It has no model of what the application's workflow is supposed to be, because that's not information the code's syntax tree contains. It can't tell you that step 3 of a checkout flow shouldn't be reachable before step 2 completes — both steps are individually well-formed code.
- DAST exercises a running application from the outside, fuzzing inputs and following links, but it has no concept of what a correct multi-step business transaction looks like versus an incorrect one that still returns
200 OK. A DAST scanner sees a coupon-code endpoint accept a request and respond successfully; it has no way to know the coupon should only be redeemable once, because "once" is a fact about the business, not about the HTTP response. - SCA matches installed dependency versions against a database of known CVEs. It's blind by design to anything that isn't a previously disclosed vulnerability in someone else's code — which is exactly the category a custom-written authorization check falls into. Your own code has never been assigned a CVE.
A human tester brings something none of the three can structurally have: a mental model of what the application is for, held simultaneously with the skill to try using it in a way its designers never intended. That combination is what finds a business-logic flaw in an API that returns a perfectly valid, perfectly well-formed 200 OK response to a request that should never have been allowed at all.
Automated scanning finds bugs in how code is written. Human testing finds flaws in what the application allows. Neither replaces the other, and running more of one never substitutes for running the other — a pipeline with a perfect SAST/DAST/SCA gate and zero human testing has excellent code hygiene and an unknown amount of exploitable business logic sitting untested in production.
Business logic flaws and chained findings, made concrete
☺ Like you're 10: One unlocked window isn't a break-in. Three separate unlocked things — a window, a side gate, and a spare key under the mat that nobody thought was a big deal alone — add up to someone walking straight to your jewelry box. A scanner checks each lock by itself and says "fine, fine, fine." A person walks the whole house.
Take a concrete, realistic example — the kind that shows up in real penetration-test reports constantly, assembled from three findings any competent scanner would each rate individually low or medium, none of which alone would block a release:
- Finding 1 — verbose error message (Low). A malformed request to
/api/profilereturns a stack trace that reveals internal user IDs are sequential integers, not UUIDs. Informational on its own; a scanner correctly flags it as low severity because nothing was disclosed except an implementation detail. - Finding 2 — IDOR on profile read (Medium).
GET /api/profile?id=1044returns another user's profile — name, email, account-recovery phone number — with no check that the requester actually owns ID 1044. A DAST scan or a SAST rule can catch the missing check if it happens to test that specific parameter with a foreign ID; many miss it because the endpoint "works correctly" for the tester's own account, which is all an authenticated crawl typically exercises. - Finding 3 — no rate limiting on OTP verification (Low).
/api/reset/verifyaccepts a 6-digit one-time code with no lockout after repeated failures. Low severity by itself — 6 digits is a million combinations, and nobody's going to sit there guessing.
A scanner reports three findings, none release-blocking. A human tester reads all three in the same afternoon and does the thing none of the scanners were built to do: combine them. Finding 1 confirms user IDs are enumerable integers. Finding 2 lets the tester walk that integer range and harvest real email addresses and phone numbers behind them. Finding 3 means that once a target email is chosen from that harvested list, the six-digit reset code guarding it can be brute-forced with no lockout, no CAPTCHA, and no alert — because nothing about a fast sequence of reset attempts trips a rule that was never written. The chain ends in a full account takeover on an arbitrary user, a finding that individually didn't exist anywhere in the pipeline's output. This is not a hypothetical pattern: it's structurally the same shape as the chain behind the Capital One breach — an SSRF finding and an over-permissioned IAM role, neither catastrophic alone, chained into exfiltration of over 100 million records.
Other common shapes of the same problem, worth recognizing on sight because a scanner will not flag any of them: a checkout that lets the client submit a negative quantity, which the server multiplies by unit price without a floor check, crediting the attacker's account instead of charging it; a multi-step wizard where posting directly to the final "complete order" endpoint skips the payment-verification step, because the server trusted the client to arrive there in order; a coupon-redemption race condition where two near-simultaneous requests both read "not yet redeemed" before either write lands, applying the discount twice. None of these are memory-safety bugs, injection flaws, or known-CVE dependencies — they're all the application doing precisely what its code says to do, which is exactly why static and dynamic analysis, built to find deviations from correct code behavior, have nothing to flag.
Penetration testing: scope, methodology, and rules of engagement
☺ Like you're 10: A penetration test is asking someone to try every doorknob in the whole building on purpose, on a day you agreed to, and write down every one that turned.
A penetration test ("pentest") is a time-boxed, authorized attempt to find and demonstrate as many exploitable weaknesses as possible within an agreed scope — breadth-first, not stealth-first. Two structured methodologies dominate real engagements and are worth knowing by name because clients and testers use them as a shared vocabulary: the Penetration Testing Execution Standard (PTES), which defines seven phases — pre-engagement interactions, intelligence gathering, threat modeling, vulnerability analysis, exploitation, post-exploitation, and reporting — and the OWASP Web Security Testing Guide (WSTG), a detailed checklist of specific test cases organized by category (authentication, session management, business logic, and so on) for web applications specifically. NIST SP 800-115 covers the same ground from a federal-guidance angle and is the one auditors most often expect a citation to. None of these are exam trivia — they're what a good pentest report cites in its methodology section so a reader can verify coverage, not just trust the tester's word.
| Knowledge level | What the tester starts with | Closest to |
|---|---|---|
| Black-box | Nothing but a URL or IP range — no credentials, no source, no architecture docs | An external attacker with zero insider knowledge |
| Gray-box | Low-privilege credentials, maybe API docs — the most common real-world scope | A malicious or compromised ordinary user |
| White-box | Full source access, architecture diagrams, and often a code walkthrough with engineers | Deepest and fastest coverage per hour billed — closest to what SAST already saw, plus judgment |
Gray-box is the default for a reason worth internalizing: a black-box test mostly measures how good the tester is at reconnaissance, which is real but not usually the scarcest skill; a white-box test can spend so much time reading code that it starts to duplicate what SAST already covered. Gray-box — a normal user account, the same access a real customer or a normal insider would have — spends the engagement's hours on the question that actually matters for a chained-findings and business-logic hunt: what can this ordinary identity be pushed into doing that it shouldn't be able to?
A penetration test without a signed authorization letter — a written rules-of-engagement document naming the exact scope, the exact dates, the exact IP ranges or hostnames in and out of bounds, and an emergency contact — is not a penetration test. It's unauthorized computer access, and in most jurisdictions that's a criminal matter regardless of intent (in the US, the Computer Fraud and Abuse Act doesn't have a "but I meant well" exception). This applies just as much internally: a well-meaning engineer who decides to "just try a few things" against a production system they don't own, without a signed scope, has created a legal and incident-response problem, not a finding.
The deliverable that actually matters is not the raw finding list — it's each finding walked through to business impact, prioritized alongside a CVSS score rather than by it alone, because a 9.8 on a system with no real data behind it can matter less than a 6.5 that reaches customer PII. See vulnerability management & triage for how those findings get scored, deduplicated against what the pipeline's own scanners already reported, and tracked to remediation in a tool like DefectDojo rather than living forever in a PDF nobody revisits.
Red teaming: an adversary emulation, not a vulnerability hunt
☺ Like you're 10: A pentest tries every door to see which ones are unlocked. A red team picks one specific prize inside the building, tries to reach it quietly, and the real question isn't "did you get in" — it's "did anyone notice."
Where a pentest asks "how many things are wrong," a red team exercise asks a narrower and harder question: "can a realistic, motivated adversary reach this one specific objective — the customer database, the code-signing key, domain admin — and if they can, does our detection and response organization notice and stop them before they do?" Scope is usually a single crown-jewel objective, not an exhaustive sweep; success is measured by whether the objective was reached and by how the defenders performed, not by a count of vulnerabilities. Stealth is part of the test — a red team that gets caught on day one and stops has still delivered a valid result, just not the one about deep access; a red team that's never detected at all has delivered a much more uncomfortable one about the detection program itself.
Real red teams don't improvise technique names — they plan and report against the MITRE ATT&CK framework, a public, continuously maintained matrix of adversary tactics (the "why" — Initial Access, Privilege Escalation, Lateral Movement, Exfiltration, and so on) and the specific techniques and sub-techniques underneath each one (the "how" — T1566 Phishing, T1055 Process Injection, T1021 Remote Services). Planning a red team engagement means selecting a realistic subset of ATT&CK techniques matching a specific adversary profile the client cares about — a ransomware crew, a nation-state actor known to target the client's sector — rather than every technique in the matrix. Execution tooling ranges from commercial command-and-control frameworks like Cobalt Strike to open-source alternatives such as Sliver, and — critically for the purple-team section below — from automated adversary-emulation platforms like MITRE Caldera and technique libraries like Atomic Red Team, which package individual ATT&CK techniques as small, safely repeatable tests rather than a full campaign.
| Penetration test | Red team | |
|---|---|---|
| Question asked | How many things are wrong, and how bad? | Can a realistic adversary reach one objective, and do defenders notice? |
| Scope | Broad — a system, an app, a network segment | Narrow — one crown-jewel objective |
| Stealth | Not usually a goal | Central to the exercise |
| Defenders informed in advance? | Usually yes | Usually no — that's the point |
| Primary output | Prioritized finding list with remediation guidance | Detection & response performance assessment against real technique attempts |
Because defenders are deliberately kept in the dark, a red team measures the whole chain of incident response & forensics under real conditions — not "would this alert have fired in theory," but "did it fire, did anyone see it, and how long did triage take" — which is a fundamentally different and more expensive signal than a pentest report can produce, and exactly why it's run far less often.
Purple teaming: the exercise that doesn't end with a PDF
☺ Like you're 10: Instead of the burglar sneaking around for a month and then mailing you a report, imagine the burglar and the security guard doing it together, in the same room, and the second the burglar gets past a camera, they both stop and go fix that camera right then — not next quarter.
A red team's stealth is also its biggest limitation as a learning exercise: because defenders don't know it's happening, a technique that sails past every detection tool undetected produces exactly one artifact — a line in a report, delivered weeks later, describing an attack path that's already gone cold by the time anyone reads it. Purple teaming fixes this by removing the secrecy on purpose. Red and blue work together, in the same session, in real time: the red side announces and executes one specific ATT&CK technique, the blue side checks — immediately, not weeks later — whether their detection stack caught it, and if it didn't, the two sides work out why together, on the same call, often against the same test environment. The "purple" name isn't a personality label for a friendlier kind of hacking; it describes literally combining red and blue into one collaborative exercise instead of two teams that only ever meet through a document.
This is exactly why purple teaming pairs so naturally with lightweight, atomic technique libraries rather than full red-team campaigns: running one Atomic Red Team test for T1003 (credential dumping) takes minutes, the blue side can check their SIEM in real time, and if nothing fired, that's this session's actionable gap — not a line item competing for attention against forty others in a report from last month.
Teams track progress across a full engagement with the public MITRE ATT&CK Navigator, a heatmap of the whole technique matrix that gets colored in as each one is tested: green for "tested and detected," red for "tested and missed," gray for "not yet exercised." Handed to leadership at the end of a quarter, that heatmap is a far more honest measure of detection coverage than "we passed our last pentest," because it names the specific techniques nobody has actually verified detection for yet — rather than implying, by omission, that everything not mentioned is fine.
On a scratch VM you're allowed to run offensive tooling on, install Atomic Red Team and pick one low-risk technique — T1082 (System Information Discovery) is a safe first choice. Run the atomic test, then go check whatever logging you already have (host event logs, an EDR trial, even just auditd) for evidence the command ran. If you find nothing, you've just personally reproduced the entire purple-team loop in miniature: you ran a real, named ATT&CK technique, and it produced zero detection signal. Now write one detection rule — even a simple auditd rule matching the command line — and re-run the exact same atomic test to confirm it fires. That's the whole discipline, at one-person, twenty-minute scale.
From technique to detection: writing the rule the exercise proved you needed
☺ Like you're 10: Finding out the smoke alarm didn't go off is only useful if you actually fix the smoke alarm before the next fire, not just write "smoke alarm broken" in a notebook.
The artifact a good purple-team session actually produces isn't the finding — it's the rule. Detection logic that closes a gap lives in one of a few concrete formats, and knowing which one applies where is a real skill in its own right, distinct from the offensive side entirely:
- Sigma rules — a generic, YAML-based, platform-agnostic detection format that converts into the query language of whatever SIEM actually runs it (Splunk, Elastic, Microsoft Sentinel). Writing detections in Sigma instead of a vendor's native query language means the rule survives a SIEM migration; the community rule set at SigmaHQ is the closest thing detection engineering has to a shared, versioned standard library.
- Falco rules — for anything the technique touches at the container or Kubernetes runtime layer, watching syscalls via eBPF for behavior no static policy could have predicted, covered in full in container runtime security.
- EDR / SIEM correlation rules — vendor-native detections (a CrowdStrike or Microsoft Defender custom rule, a correlation search spanning multiple log sources) for anything that needs signal fusion a single log source can't provide alone.
Take the OTP-brute-force chain from earlier as a worked example. The gap the purple-team session exposes isn't "the endpoint has no rate limit" — the team already knew that from the pentest finding. The gap is "we have no detection for what exploiting that gap actually looks like on the wire," which is a different and more durable fix than patching the one endpoint, because it also catches the next endpoint someone forgets to rate-limit:
title: High-Volume Sequential OTP Verification Attempts
id: 3f2c9e40-88b1-4b1a-9a7e-example-only
status: experimental
description: >
Detects a high rate of failed one-time-code verification attempts against
a single account within a short window — the network-level signature of
the OTP brute-force chain identified in the purple-team session against
the password-reset flow (chained with the IDOR-driven account enumeration).
logsource:
category: application
product: web
detection:
selection:
http.url|contains: '/api/reset/verify'
http.response.status: 401
timeframe: 5m
condition: selection | count(client_ip, target_account) by target_account > 15
level: high
tags:
- attack.credential_access
- attack.t1110.003 # password spraying / guessing sub-techniqueNotice what changed: before the purple-team session, "no rate limit on the OTP endpoint" was a finding sitting in a triage backlog, competing for engineering time against every other medium-priority item. After it, there's a deployed rule that fires the moment anyone — an automated attacker, a red team next quarter, a real incident — attempts the exact technique that was proven to work, regardless of whether the underlying rate-limit bug has been fixed yet. That's the actual value purple teaming adds on top of a pentest report: a pentest tells you a door is unlocked; a purple-team session gets you an alarm on that door today, whether or not the lock gets replaced this sprint.
Where offensive security sits in the DevSecOps cadence
☺ Like you're 10: You brush your teeth every day, but you only go to the dentist twice a year — both matter, and neither one is a substitute for the other.
A common and costly misunderstanding is treating offensive security as one more gate that should be squeezed into the CI/CD pipeline the same way SAST, DAST, and SCA are. It structurally can't work that way: a competent pentest takes days to weeks of skilled human time, and a red team engagement can run for months by design — neither fits inside a merge-blocking check that has to return a result before a developer's coffee gets cold. What actually replaces "run it on every commit" is a deliberate cadence, layered by cost and depth, matched to how often each layer's signal actually changes:
| Layer | Typical cadence | What triggers an off-cycle run |
|---|---|---|
| SAST / DAST / SCA | Every commit, continuously | N/A — this is the continuous baseline |
| Penetration test | Quarterly, or per major release | A significant new feature, a new external-facing system, a compliance deadline |
| Purple-team session | Monthly to quarterly, scoped to a handful of techniques | A new gap surfaces in threat intel, or as prep before a red team |
| Red team | Annually, or semi-annually for high-maturity programs | A major architecture change, an acquisition, evidence of targeting by a specific threat actor |
The layers aren't independent, either — each one should feed the next. Findings a pentest turns up feed straight into vulnerability management and triage for remediation tracking. The techniques a red team used to reach its objective, whether or not it was caught, become the exact technique list a purple team schedules next quarter to verify detection coverage before the next real red team run. And secure by design and threat intelligence is what should be steering which ATT&CK techniques and which crown-jewel objectives get chosen in the first place — a red team scoped against threats nobody targeting your sector actually uses is an expensive exercise that teaches you very little.
Automated scanning is a daily habit; offensive security is a periodic, deliberately deep audit. A mature program doesn't choose one over the other and doesn't try to force the audit into the daily habit's rhythm — it runs both on the cadence each one actually needs, and wires the output of the deep audit back into what the daily habit and the detection stack both watch for.
Timmy the Turtle: Every gate's green. SAST, DAST, SCA — nothing above medium in six weeks. I don't see what's left to worry about.
Rocky the Raccoon: Spent an afternoon on the reset flow. Found a verbose error, an IDOR, and no rate limit on the OTP check — three things your gates each shrugged at.
Timmy the Turtle: Individually, none of those trip a merge block. I checked our thresholds.
Rocky the Raccoon: Together they're an account takeover on anyone I pick. That's the part your thresholds can't see — I had to actually try using the app wrong.
Foxy: So if this were a real attacker instead of Rocky on the clock, would we even have noticed?
Rocky the Raccoon: That's next month's purple-team session. I run the exact chain again, you watch your SIEM in real time, and whatever doesn't fire, we fix on the call — not in a report you read in March.
Professor Owl: Say the shape of it plainly: scanners find deviations from correct code. Rocky finds deviations from correct intent. Neither one is optional, and only one of them tells you whether Foxy would ever have known.
1. Give the structural reason — not just "they're less thorough" — that SAST, DAST, and SCA cannot find a business-logic flaw like a skippable checkout step. 2. Walk through the three-finding OTP chain and explain why each finding individually would be rated low or medium, and why the chain rates critical. 3. What's the actual difference in the question being asked between a penetration test and a red team, beyond "red team is stealthier"? 4. Why does a red team's own stealth limit its value as a learning exercise, and what does purple teaming change structurally to fix that? 5. In the Sigma rule example, what changed about the OTP-brute-force risk between "we have a pentest finding for it" and "we have a deployed detection rule for it" — and why does that difference matter even before the underlying bug is patched?
Check your answers
- SAST reasons about source code without a model of intended workflow order; DAST reasons about individual HTTP responses without a model of correct multi-step business state; SCA only matches known CVEs in third-party code. None of the three has any representation of "what this application is supposed to let a user do," so a flaw that requires exactly that judgment — recognizing that reachable code is being reached in the wrong sequence — falls outside what any of them can evaluate, no matter how well-tuned their rules are.
- Each finding is individually low-impact: a verbose error only leaks an implementation detail, an IDOR on a read-only profile endpoint leaks contact info but not credentials, and a missing rate limit is only dangerous if there's something worth brute-forcing behind it. Chained, they become a full attack path — enumerate valid accounts via the ID leak, harvest targets via the IDOR, then brute-force the OTP behind a specific target's email — reaching a critical outcome (account takeover) that doesn't exist in any single finding's own scope.
- A pentest asks "how many things are wrong and how bad, across a broad scope, in the open." A red team asks "can a realistic adversary reach one specific objective, and do our defenders detect and stop them" — narrower in scope, but the object under test is the whole detection-and-response organization, not just the application's vulnerability count. Stealth is a means to that end, not the whole difference.
- Because defenders are deliberately not told a red team is happening, a technique that goes completely undetected produces no immediate feedback — it becomes one line in a report delivered weeks after the fact, describing an attack path that's already stale. Purple teaming removes the secrecy: red and blue run the same techniques together, in real time, so a detection gap is identified and can be fixed with a new or tuned rule in the same session, not discovered cold from a document later.
- Before the rule: the risk existed only as a backlog item — "OTP endpoint has no rate limit" — that provides no protection until an engineer gets around to fixing the underlying endpoint. After the Sigma rule is deployed: the exact technique that was proven to work now triggers an alert the moment anyone attempts it — the next red team, an actual attacker, or a similar bug in some other endpoint entirely — regardless of whether the original rate-limit bug has shipped a fix yet. The detection is a safety net that exists independently of, and faster than, the underlying code fix.