▣ FastLane / SpeedBump

Lightning Lesson

Run the live demo yourself

This is the exact live demo from Casky's free Lightning Lesson, "Your Vibe-Coded App Is Already Compromised. Did You Find It?": a synthetic vibe-coded SaaS running in a container, two scripted checks that find its RLS gap and its leaked secret, then a real Casky investigation of the same evidence, evidence through to a CISO-ready report. Nothing here touches a real company; everything runs on your own machine.

The Loopline homepage

Loopline is a fictional customer-support SaaS, "vibe-coded" in a weekend and shipped straight to its first 40 customers, no security review, per the FastLane / SpeedBump story. It ships two real gotchas from the sourced Top 10: Row-Level Security left off, and a Supabase service-role key sitting in the client bundle.

Prerequisites

Pull and run it

cd casky-workshops/fastlane

# Pull the pre-built image from GHCR (rebuilt nightly with the latest patches) instead
# of building locally — much faster at a live session.
docker pull ghcr.io/casky-ai/casky-loopline:latest
docker tag ghcr.io/casky-ai/casky-loopline:latest casky-loopline

docker run -d --name casky-loopline -p 8787:8787 casky-loopline

# Fallback, kept for reference — rebuild locally if you're iterating on Dockerfile.demo
# itself, or if GHCR is unreachable (offline/air-gapped venue):
#   docker build -f Dockerfile.demo -t casky-loopline .

Open http://localhost:8787, Loopline's own landing page: dark CyberForge theme, checkered-flag stripe, and a plainly-labeled synthetic-demo notice at the bottom.

Verified end-to-end

docker pull ghcr.io/casky-ai/casky-loopline:latest confirmed working (no docker login needed, publicly pullable). Homepage returns 200, both scripts below return the expected finding, no manual fixups needed.

How Loopline broke it

Lovable scaffolded Loopline's database. It never turned Row-Level Security on for the customers table, not disabled by a developer, never enabled at all. Weeks later, a security blog post scared the founder into fixing one table: tickets got a policy, but it was USING (true), which matches every row for every requester. Looks fixed in a schema diff. Isn't. customers was never revisited.

Separately, an env var named NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY shipped Supabase's admin key straight into the browser bundle, because the coding assistant didn't flag what NEXT_PUBLIC_ does in Next.js. Nobody caught it before it shipped. Full story: NARRATIVE.md.

The five-minute check

Two scripts, no special access, same two checks from the Top 10 blog post, already in fastlane/, pointed at the local container instead of a real app.

Check 1: does the anon key read every row?

cd casky-workshops/fastlane
./check_1_rls.sh

Runs curl -s "http://localhost:8787/rest/v1/customers?select=*" -H "apikey: <anon key>" and explains the result. Returns all five Loopline customer rows, no login required. The apikey is the public "anon" key, meant to ship to every browser. rowsecurity: false is Postgres's own flag: RLS was never turned on for this table, so the public key alone is enough to read everything.

Check 2: is a secret sitting in the shipped bundle?

./check_2_secrets.sh

Runs curl -s http://localhost:8787/_next/static/chunks/app-a91f3c2e.js | grep -oiE '(service_role|sk-live-|AKIA)[A-Za-z0-9_.":-]{5,}' and explains the result. Returns the Supabase service-role key: Supabase's admin key, meant only for trusted server-side code. The anon key (check 1) respects RLS when RLS is configured; the service-role key bypasses RLS entirely, by design, correctly configured or not.

This is synthetic data

The customer rows, the domain, and the keys above are all fabricated for this workshop (see NARRATIVE.md). No real company, customer, or credential is involved.

Now let Claude find it

The two checks above are deterministic — curl and grep, no AI involved, so the result doesn't depend on trusting an agent. Here's the other half: point Claude Code at the same two pieces of evidence with a plain-English ask, no hints beyond the filenames, and watch it reach the identical findings on its own.

Setup

cd casky-workshops/fastlane

# Your own key, unquoted — this path doesn't need casky-box/Section 2 set up first.
echo 'ANTHROPIC_API_KEY=sk-ant-...' > .env

docker pull ghcr.io/casky-ai/casky-fastlane:latest
docker tag ghcr.io/casky-ai/casky-fastlane:latest casky-fastlane
docker run -d --name casky-fastlane --env-file .env -v "$(pwd)":/root/fastlane casky-fastlane

docker exec -it -w /root/fastlane casky-fastlane bash
#   ...now inside the container:
export PATH="$HOME/.local/bin:$PATH"
claude

The prompt

You are auditing Loopline, a Supabase-backed customer-support SaaS. I have two pieces of
evidence in this folder: app/rls-policies.json (a Postgres RLS policy export) and
app/client-bundle-excerpt.txt (strings pulled from the production client-side JS bundle).
Investigate both files, tell me what security issues you find, which skill(s) you used, why
each issue matters, and how to fix it. Be concise.
Verified just now

Claude Code, given only that prompt (10 skills mounted, no other hints), named both gotchas correctly and cited the skills it used — testing-api-for-broken-object-level-authorization for the RLS gap, testing-for-sensitive-data-exposure for the bundle secret — with the same fix each check's own explanation gives: rotate the service-role key and move it server-side; ALTER TABLE customers ENABLE ROW LEVEL SECURITY with an org-scoped policy. Unprompted, it also cross-referenced app/access-log.txt to confirm the service-role key wasn't just present but actually used (1,842 rows pulled in one request), and caught a third, related bug sitting in the same RLS export — tickets' policy is enabled but reads USING (true), which matches every row for every requester — while explicitly noting it only reviewed the two files named and offering to go further.

exit the claude session and the container shell (two exits) when you're done, then docker rm -f casky-fastlane — or see Cleanup on the Troubleshooting page.

Evidence to CISO report

That was one container, one prompt, two gotchas. Here's the same evidence run through Casky's full pipeline instead — the flow every other Casky workshop uses:

#StageWhat happens
1EvidenceThe check output above, saved as-is. No scoping, no cleanup, just what a real attacker would have.
2Skill matchingCasky's classifier reads the evidence and selects the right skills from the 818-skill library, no manual picking.
3ActionsEach selected skill actually runs. Every tool call is logged and independently verified ([VERIFIED] Skill script executed: YES/NO).
4RemediationSpecific, prioritized fixes: enable RLS on customers, rotate the service-role key, move it server-side.
5CISO reportAn executive summary, mapped to MITRE ATT&CK and NIST CSF, the format a board asks for after every incident.

Two independent paths run this pipeline against this exact evidence, both already verified. Pick whichever matches your setup; full steps live on the Setup page:

PathWhat it needsWhat you get
Section 1: Kali + Claude Code Docker, fastlane/.env Interactive Claude Code session, 10 hand-picked skills, ./verify.sh at 12/12 PASS
Section 2: Casky Box Casky Box running (casky-box/, pulled from GHCR) casky harness --auto over all 818 skills, auto-classified, MITRE-mapped findings, a CISO-ready executive summary
Verified just now

Section 2, run against this exact evidence, independently found 7 MITRE techniques at 84.5% confidence and, unprompted, asked whether Loopline's RLS default "matches the known CVE-2025-48757 pattern": stage 2 (skill matching) converging on the real incident this scenario is modeled on, from the evidence alone. Full transcript on the Setup page. Open casky-ui (http://localhost:8766) afterward for the Plan / Execution / Findings / Remediation tabs, stages 3 and 4 above, and the CISO-ready executive summary, stage 5.


Cleanup

docker stop casky-loopline && docker rm casky-loopline

Non-destructive, nothing else on your machine is touched. For the Casky investigation containers, see Cleanup on the Troubleshooting page.

← Back to the full FastLane / SpeedBump story