Engineering

What We Learned

A few takeaways from this rebuild:

Decouple aggressively. Every service boundary we drew paid for itself. When we needed to swap SES for a different email provider in one region, it was a change to the delivery worker only. Nothing else knew or cared.

Design for the burst, not the average. Our average click rate is modest. Our peak click rate in the first five minutes of a campaign is 50x the average. If you design for the average, you'll fall over during the peak.

Observability isn't optional. We instrument everything — queue depth, delivery latency percentiles, click-to-capture time, Kafka consumer lag. When something goes wrong at 2am, dashboards are the difference between a 5-minute fix and a 2-hour investigation.

Keep the hot path dumb. The click tracker does almost nothing. That's the point. The less work you do in the critical path, the more abuse it can absorb.

What's Next

We're currently working on expanding the simulation engine to support additional attack vectors beyond email — think SMS-based smishing, voice phishing (vishing) via AI-generated calls, and multi-channel attack chains that mimic how real adversaries operate. The architecture we've built gives us a solid foundation to plug in new delivery channels without rearchitecting the core pipeline.

If this kind of work sounds interesting to you, we're hiring across the engineering team. Check out our careers page for open roles.

batman
from anthropic import Anthropic

client = Anthropic()


def generate_phishing_content(
    employee_context: dict,
    attack_vector: str,
    difficulty: str,
) -> dict:
    """Generate personalized phishing email content.

    Args:
        employee_context: Role, department, recent activities
        attack_vector: Type of attack (credential harvest, malware, BEC, etc.)
        difficulty: Easy, medium, or hard — controls subtlety of social engineering cues
    """
    prompt = build_phishing_prompt(employee_context, attack_vector, difficulty)

    response = client.messages.create(
        model="claude-sonnet-4-5-20250514",
        max_tokens=1024,
        messages=[{"role": "user", "content": prompt}],
    )

    content = parse_structured_response(response.content[0].text)

    return {
        "subject_line": content["subject"],
        "html_body": content["body"],
        "sender_name": content["sender_display_name"],
        "difficulty_signals": content["red_flags"],
    }
We are hiring
Build the future of cybersecurity for AI.
See open roles
adaptive staff sitting at a board table
two adaptive employees conversing in front of their computers
a group photo at a rock climbing gym
a group photo on a boat in the ocean
people smiling on a bus
people sitting drinking coffee in front of a computer in an office environment
two people talking in a night club environment
people in an office environment
two men talking in an office environment
a group photo in a beach setting
two people playing ping pong
people smiling in an office setting
a man smiling in front of a platter of pastries
a group of people sitting on lounge furniture
Label