Bootcamp
A 60-minute OWASP bootcamp: a structured pass over one repo that catches the most common Top 10 bugs and ships fixes. Run it on a real branch with a colleague.
A 60-minute OWASP review bootcamp
EXAMPLE
# ===== Objectives =====
# 1. Run a structured Top 10 review on a real repo
# 2. Ship at least one fix per finding
# 3. Add CI gates so the same bug class cannot reappear
# ===== 0-10 min: A01 Broken Access Control =====
# Grep for missing ownership checks:
git grep -nE 'find\(|findOrFail\(|getById\(|byId\(' | head
# For each hit:
# - Does the query scope by current_user / request.user / authenticated id?
# - If no -> add the scope. write a test.
# Example fix:
# - Order::find($id)
# + $request->user()->orders()->findOrFail($id)
# ===== 10-20 min: A02 Cryptographic Failures =====
git grep -nE 'sha1|md5\(.*password|simple_encrypt'
# Replace any password hash with password_hash(..., PASSWORD_ARGON2ID)
# Replace any AES-CBC without HMAC with AES-GCM
# Replace any '==' on secrets with hash_equals / timingSafeEqual
# ===== 20-30 min: A03 Injection =====
git grep -nE 'whereRaw|sequelize.query|cursor\.execute.*\+|DB::statement.*$' | head
# Verify each is parameterised; whitelist any ORDER BY/identifier from input.
# ===== 30-40 min: A05 Security Misconfiguration =====
# - APP_DEBUG=false in production .env
# - .env file mode 0600
# - Removed default credentials in seeds
# - Stack traces NOT shown to users
# - CSP header set
# Add a CI check:
# scripts/check-prod-env.sh:
# if grep -E '^(APP_DEBUG|DEBUG)=true' .env.production; then exit 1; fi
# ===== 40-50 min: A06 Vulnerable & Outdated Components =====
composer audit
npm audit --omit=dev
# Open ONE patch PR per upgrade. Schedule weekly: Renovate/Dependabot config.
# ===== 50-60 min: A07 Authentication + A09 Logging =====
# - Login rate limit?
# - Session rotation on password change / role change?
# - MFA available?
# - auth_failure events logged?
# Sample fix (Laravel):
# class LoginController {
# public function store(Request $r) {
# $validated = $r->validate(['email'=>'required|email','password'=>'required']);
# if (!Auth::attempt($validated, $r->boolean('remember'))) {
# Log::channel('security')->warning('auth_failure',
# ['email'=>$validated['email'],'ip'=>$r->ip()]);
# return back()->withErrors(['email'=>'invalid']);
# }
# $r->session()->regenerate();
# return redirect()->intended('/dashboard');
# }
# }
# ===== Bonus 10 min: A10 SSRF =====
# Find server-side fetch of user URLs:
git grep -nE 'file_get_contents\(\$|HttpClient.*->get\(\$|curl_init\(\$|request\(.*\$'
# Validate scheme, deny private IPs, deny redirects to new origins, IMDSv2 on EC2.
# ===== Post-bootcamp: CI gates =====
# 1) Semgrep with the OWASP ruleset on every PR:
# - name: semgrep
# uses: returntocorp/semgrep-action@v1
# with: { config: 'p/owasp-top-ten' }
#
# 2) Composer/NPM audit on every PR
# 3) Dependency dashboard via Renovate / Dependabot
# 4) Security log alerts in the SIEM
# 5) Pen test annually; bug bounty for ongoing coverage
# ===== Deliverables =====
# - PR with at least one fix per Top 10 category found
# - CHANGELOG entry: 'security: review pass for OWASP Top 10'
# - Issues opened for items deferred (with risk grading)
# - New CI rules merged so the bug class cannot reappear silently
# ===== Pitfalls =====
# - Marking issues 'wont fix' because exploitation 'seems hard' -> the bug is
# still there next quarter when the exploit is published
# - Running the bootcamp without writing tests -> regressions slip in
# - Outsourcing entirely to a scanner -> false sense of security; manual
# review catches what scanners miss
Why it matters
Convert every Top 10 finding into a unit test. The PR that fixes the bug also ships the test that proves the fix; the next refactor cannot quietly re-introduce it. After a few bootcamp rounds, your test suite IS your security posture — and that posture survives team changes that no informal checklist would.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…