Sangamesh.Dandin
All projects

Case 04 / 09Phishing simulationCompleted

SPEARSIM.

Privacy-minded phishing simulations with follow-up training.

A phishing-simulation platform for security-awareness programmes. Employees are imported from a CSV checked against the organisation's domain and given pseudonymous aliases, so the LLM (Groq) only ever sees an alias and a role, never a name or address. An admin must record consent before a campaign can launch. Emails go out through SendGrid, opens and clicks are tracked by UUID, and anyone caught gets a short awareness quiz. It also has role-based access, audit logging, erasure by alias and automatic deletion of campaign data after 90 days.

What I built

  • Designed the privacy model: domain-checked CSV import, pseudonymous aliases, and LLM prompts that carry only an alias and a role.
  • Built Supabase auth with three roles, a consent gate before launch, audit logging, erasure by alias and 90-day retention cleanup.
  • Built the email pipeline (Groq generation and SendGrid delivery through Celery, with an inline fallback), the tracking endpoints and the awareness quiz.
Problem
Phishing risk
Built with
React, FastAPI, Supabase
Result
End-to-end campaigns
  • Python
  • FastAPI
  • React
  • Supabase
  • Groq
  • SendGrid
  • Celery

▶Demo

See it work.

An animated walkthrough of the interface, not a screen recording. The company, people and emails shown are fictional examples.

01Architecture

How it's built.

Drawn from the project's source code, not its README: what each part actually does and how a request moves through it.

SpearSim campaign data boundaries An admin console drives a FastAPI campaign API that pseudonymises employees and gates launch on recorded consent; an email pipeline sends only aliases and roles to Groq and real addresses to SendGrid; employees interact through public tracking endpoints that record event flags and quiz scores in Supabase Postgres, which a retention Edge Function purges after 90 days; four verified implementation limits are listed. LIFECYCLE 01Org + campaign→02CSV → aliases→03Consent gate→04Generate→05Send→06Open · click · cred→07Awareness quiz→08Report + advice THIRD-PARTY PROCESSORS SPEARSIM BACKEND · FASTAPI + CELERY / REDIS SUPABASE JWT LAUNCH REMEDIATION ALIAS + ROLE SUBJECT + HTML TO + HTML SIMULATION UUID CSV ROWS EMPLOYEE ROWS EVENTS · QUIZ Admin console React · Supabase Auth JWT → 3 roles ethical-use terms gate STEPS 04 · 08 Groq llama-3.3-70b-versatile (GROQ_MODEL default) subject + HTML body · remediation advice STEP 05 SendGrid POST /v3/mail/send X-PhishSim-Authorized header own open/click tracking off STEPS 01–03 · 08 Campaign & GDPR API routes/campaigns, employees, gdpr CSV email must match org domain Employee_XXXX alias per row launch requires consent_signed L1 erasure by alias (admin role) audit row per console action risk: cred High · click Medium report advice regenerated per view STEPS 04–05 Email pipeline Celery task · inline fallback Groq: ≤ 5 employees at once HTML sanitised by bleach + open pixel, click link SendGrid: ≤ 10 at once failed generations skipped STEPS 06–07 Tracking endpoints public · no auth · 3 rate-limited GET/track/open/{uuid} GET/track/click/{uuid} POST/track/cred/{uuid} L3 POST/api/track/quiz/{uuid} stores event, IP, user agent first event per type only Employee inbox → /phish/{uuid} no form data sent awareness red flags 3-question quiz score set in browser retention-cleanup Supabase Edge Function deletes campaigns past auto_delete_at (+90 d) cron set in dashboard STORE Supabase Postgres · backend uses the service-role key campaignsconsent_signed · auto_delete_at employeesalias · email · role · uuid L4 name_mapalias → real_name (TEXT) L2 eventstype · IP · user agent quiz_resultsscore 0–3 · answers audit_logsactor · action · IP · metadata Groq never receives a name or email: prompts carry the alias, the CSV role and the organisation name. The fake login posts no form fields. Requests carry the tracking UUID; the quiz adds its score and answers. VERIFIED LIMITS · FOUND IN CODE, NOT STATED IN THE README L1 Launch checks consent_signed only. The authorisation-PDF download is required by the browser wizard, not by the API. L2 name_map.real_name is a plain TEXT column. The Supabase Vault encryption mentioned in comments is not set up in the repository. L3 The phish page posts to /api/track/cred, but the backend route is /track/cred, so credential events may go unrecorded (static analysis). L4 RLS policies let the anon role SELECT every employees row, including email addresses. The backend bypasses RLS entirely. LEGEND Person SpearSim service Where the controls live Third-party API Data store Trust zone Pseudonymised prompt Data flow Response L1 Verified limit

Read from the code at commit dcdd0c0 · Open full size ↗

02Under the hood

How it works.

  1. 01

    Consent

    An admin records consent before a campaign can launch

  2. 02

    Generate

    Groq writes each email from an alias and a role, never a name

  3. 03

    Send & track

    SendGrid delivers; opens and clicks are tracked by UUID

  4. 04

    Train

    Scenario red flags and a short awareness quiz

→Up next · 05 / 09

Next project.

MailGuard AI — Gmail impersonation detection with SPF, DKIM and DMARC checks.

Back to all projects