WORKFLOW LIBRARY

Security automation,
ready to run.

Real workflows. Not demos. Click Run Demo on any live card — watch the AI engine analyze phishing emails, flag impossible travel, identify malware, or triage suspicious URLs and generate containment plans in real time.

LIVE trigger: email_received

Phishing Email Triage

Full-stack phishing analysis: extract IOCs, enrich URLs against URLhaus, classify intent with GPT-4o-mini, score 0–100, route to quarantine or monitor. 9 steps, ~8 seconds end-to-end.

9 steps · ~8s runtime · GPT-4o-mini classifier
phishing-triage.yaml
name: Phishing Email Triage
version: "1.0"
trigger: email_received
inputs:
  - name: sender
  - name: subject
  - name: body
  - name: headers
  - name: attachments

steps:

  # 1-4. Extract IOCs (URLs, IPs, emails, base64)
  - id: extract_urls
    type: regex.extract
    with:
      input: "{{ inputs.body }}"
      pattern: "https?://[^\s\"'<>)\]\}]+"
      global: true

  - id: extract_ips
    type: regex.extract
    with:
      input: "{{ inputs.body }} {{ inputs.headers }}"
      pattern: "\\b(IP address pattern)\\b"
      global: true

  - id: extract_emails
    type: regex.extract
    with:
      input: "{{ inputs.body }}"
      pattern: "[a-zA-Z0-9._%+\\-]+@[a-zA-Z0-9.\\-]+\\.[a-zA-Z]{2,}"
      global: true

  - id: extract_base64
    type: regex.extract
    with:
      input: "{{ inputs.body }}"
      pattern: "[A-Za-z0-9+/]{40,}={0,2}"
      global: true

  # 5. URLhaus reputation (no API key needed)
  - id: enrich_urls
    type: http.post
    on_failure: continue
    with:
      url: "https://urlhaus-api.abuse.ch/v1/url/"
      headers:
        Content-Type: "application/x-www-form-urlencoded"
      body:
        url: "{{ steps.extract_urls.output.all[0] }}"

  # 6. LLM intent classification
  - id: analyze_intent
    type: llm.analyze
    with:
      model: gpt-4o-mini
      temperature: 0.1
      json_output: true
      system: "You are a senior email security analyst..."
      prompt: "Classify this email. Return JSON: classification, confidence, reasoning, signals"

  # 7. Combine IOC + LLM into 0-100 risk score
  - id: score
    type: transform
    with:
      compute:
        ioc_component: "min(url_count*15,30) + min(ip_count*10,10) + base64_bonus"
        llm_component: "confidence * direction_factor * 0.6"
        final_score:   "clamp(ioc + llm, 0, 100)"
        severity:      "score>=70?critical : score>=40?high : score>=20?medium : low"

  # 8. Route: quarantine if score >= 70, else monitor
  - id: route
    type: conditional
    with:
      if: "steps.score.output.final_score >= 70"

  # 9a/9b. Output verdict with IOCs and LLM reasoning
  - id: recommend_quarantine
    type: output
    if: "steps.route.output.result == true"
    with:
      value:
        verdict:             "{{ steps.analyze_intent.output.parsed.classification }}"
        recommended_action: quarantine
        score:               "{{ steps.score.output.final_score }}"
        severity:            "{{ steps.score.output.severity }}"
        llm_reasoning:      "{{ steps.analyze_intent.output.parsed.reasoning }}"
        phishing_signals:   "{{ steps.analyze_intent.output.parsed.phishing_signals }}"
        legitimate_signals: "{{ steps.analyze_intent.output.parsed.legitimate_signals }}"

  - id: recommend_monitor
    type: output
    if: "steps.route.output.result == false"
    with:
      value:
        verdict:             "{{ steps.analyze_intent.output.parsed.classification }}"
        recommended_action: monitor
        score:               "{{ steps.score.output.final_score }}"
        severity:            "{{ steps.score.output.severity }}"
        llm_reasoning:      "{{ steps.analyze_intent.output.parsed.reasoning }}"
        phishing_signals:   "{{ steps.analyze_intent.output.parsed.phishing_signals }}"
        legitimate_signals: "{{ steps.analyze_intent.output.parsed.legitimate_signals }}"

Run Demo

Submit a suspicious email. The engine runs all 9 steps live.

LIVE trigger: alert_triggered

Suspicious Login Investigation

Impossible-travel detection: geolocates current and prior login IPs, computes haversine distance and km/h, diffs device fingerprints, classifies risk with GPT-4o-mini, routes to block+MFA-reset, challenge, or monitor. 8 steps, ~6 seconds end-to-end.

8 steps · ~6s runtime · ip-api.com + GPT-4o-mini
suspicious-login.yaml
name: Suspicious Login Investigation
trigger: alert_triggered
inputs:
  - name: user_id
  - name: ip
  - name: user_agent
  - name: timestamp
  - name: last_known_ip
  - name: last_known_location
  - name: last_login_at

steps:

  # 1. Parse and normalize event fields
  - id: parse_event
    type: transform

  # 2. Geolocate current IP (ip-api.com, no key)
  - id: geoip_enrich
    type: http.get
    with:
      url: "http://ip-api.com/json/{{ inputs.ip }}?fields=status,country,city,lat,lon,isp,proxy,hosting"

  # 3. Geolocate prior known-good IP
  - id: geoip_enrich_prior
    type: http.get
    with:
      url: "http://ip-api.com/json/{{ inputs.last_known_ip }}?fields=status,country,city,lat,lon,isp,proxy,hosting"

  # 4. Haversine distance + impossible travel flag (>900 km/h)
  - id: impossible_travel
    type: transform
    with:
      compute:
        distance_km:   "haversine(lat1, lon1, lat2, lon2)"
        elapsed_hours: "(timestamp2 - timestamp1) / 3600000"
        speed_kmh:     "distance_km / elapsed_hours"
        is_impossible: "speed_kmh > 900 ? 'true' : 'false'"

  # 5. Parse OS/browser from user-agent strings
  - id: device_diff
    type: transform
    with:
      compute:
        current_os:      "parseOS(ua)"
        current_browser: "parseBrowser(ua)"
        device_changed:  "current_os !== prior_os ? 'true' : 'false'"

  # 6. GPT-4o-mini risk classification
  - id: llm_reasoning
    type: llm.analyze
    with:
      model:       gpt-4o-mini
      json_output: true
      prompt:      "Classify: benign|suspicious|malicious. Return JSON: classification, confidence, reasoning, risk_signals, benign_signals"

  # 7. Combine into 0-100 score (travel:40 + vpn:20 + device:15 + llm:25)
  - id: risk_score
    type: transform
    with:
      compute:
        final_score: "clamp(travel_pts + vpn_pts + device_pts + llm_pts, 0, 100)"
        severity:    "score>=70?critical : score>=40?high : medium"

  # 8a. score≥70 → block + force MFA reset
  - id: block_and_force_mfa_reset
    type: output
    if: "steps.risk_score.output.final_score >= 70"

  # 8b. 40–69 → challenge with MFA step-up
  - id: challenge_mfa
    type: output
    if: "steps.risk_score.output.final_score < 70"

Run Demo

Lagos login 9 minutes after Seattle — watch the engine flag impossible travel and block the account.

LIVE trigger: alert_triggered (EDR)

Malware Hash Lookup & Containment

Paste a SHA256 hash: validates format, queries MalwareBazaar (no key required), extracts malware family, scores severity 0–100 with GPT-4o-mini MITRE ATT&CK mapping, and emits a structured containment plan. 7 steps, ~6 seconds.

7 steps · ~6s runtime · MalwareBazaar + GPT-4o-mini
malware-hash-lookup.yaml
name: Malware Hash Lookup & Containment
trigger: alert_triggered
inputs:
  - name: sha256
  - name: host_id
  - name: process_name
  - name: observed_at

steps:

  # 1. Normalize inputs
  - id: parse_input
    type: transform

  # 2. Validate SHA256 format (64 hex chars)
  - id: validate_hash
    type: regex.extract
    with:
      input: "{{ inputs.sha256 }}"
      pattern: "^[a-fA-F0-9]{64}$"

  # 3. MalwareBazaar hash lookup (POST, no API key)
  - id: malwarebazaar_lookup
    type: http.post
    on_failure: continue
    with:
      url: "https://mb-api.abuse.ch/api/v1/"
      headers:
        Content-Type: "application/x-www-form-urlencoded"
      body:
        query: get_info
        hash:  "{{ inputs.sha256 }}"

  # 4. Extract family from signature/tags (Emotet, TrickBot, Cobalt Strike…)
  - id: family_classification
    type: transform
    with:
      compute:
        family: "matchKnownFamily(signature + tags)"
        first_seen: "{{ steps.malwarebazaar_lookup.output.body.data[0].first_seen }}"

  # 5. GPT-4o-mini: description, host impact, MITRE ATT&CK, containment bullets
  - id: llm_summary
    type: llm.analyze
    with:
      model:       gpt-4o-mini
      json_output: true
      prompt:      "Given MalwareBazaar data for {{ steps.family_classification.output.family }}, return JSON: description, host_impact, mitre_techniques[], containment_steps[]"

  # 6. Score 0–100: known family (40) + recent (20) + in bazaar (20) + vendor hits (20)
  - id: severity_score
    type: transform
    with:
      compute:
        score:    "clamp(family_pts + recent_pts + bazaar_pts + vendor_pts, 0, 100)"
        severity: "score>=70?critical : score>=40?high : medium"

  # 7. Emit containment plan: isolate_host, kill_process, block_hash_at_edr, quarantine_file
  - id: containment_plan
    type: output
    with:
      value:
        family:           "{{ steps.family_classification.output.family }}"
        score:            "{{ steps.severity_score.output.score }}"
        mitre_techniques: "{{ steps.llm_summary.output.parsed.mitre_techniques }}"
        actions:
          isolate_host:      "{{ inputs.host_id }}"
          block_hash_at_edr: "{{ inputs.sha256 }}"
          kill_process:      "{{ inputs.process_name }}"
          quarantine_file:   "{{ inputs.process_name }}"

Run Demo

Submit a known Emotet hash. The engine queries MalwareBazaar, classifies the family, and generates a containment plan in real time.

LIVE trigger: alert_triggered (proxy / SIEM)

Phishing URL / Domain Reputation Triage

Paste any URL: normalizes it, checks domain age via RDAP, queries URLhaus for known-malicious matches, inspects TLS cert metadata, detects homoglyph brand lookalikes, classifies with GPT-4o-mini (MITRE T1566.002), scores 0–100, and emits a structured proxy/DNS block + inbox quarantine plan. 8 steps, ~8 seconds.

8 steps · ~8s runtime · RDAP + URLhaus + crt.sh + GPT-4o-mini
phishing-url-triage.yaml
name: Phishing URL / Domain Reputation Triage
trigger: alert_triggered
inputs:
  - name: url
  - name: brand_list

steps:

  # 1. Normalize URL — strip tracking params, extract host/domain
  - id: url_normalize
    type: transform
    with:
      compute:
        hostname:   "new URL(inputs.url).hostname"
        domain:     "hostname.split('.').slice(-2).join('.')"
        has_ip_host: "/^\\d+(\\.\\d+){3}$/.test(hostname)"

  # 2. Domain age via RDAP (free, no key) — flag domains < 30 days old
  - id: domain_age_check
    type: http.get
    on_failure: continue
    with:
      url: "https://rdap.org/domain/{{ steps.url_normalize.output.domain }}"

  # 3. URLhaus lookup — known-malicious URL + host (no API key)
  - id: urlhaus_lookup
    type: http.post
    on_failure: continue
    with:
      url: "https://urlhaus-api.abuse.ch/v1/url/"
      headers:
        Content-Type: "application/x-www-form-urlencoded"
      body:
        url: "{{ steps.url_normalize.output.url_clean }}"

  # 4. TLS cert check via crt.sh — flag self-signed / LE < 7 days
  - id: tls_cert_check
    type: http.get
    on_failure: continue
    with:
      url: "https://crt.sh/?q={{ steps.url_normalize.output.domain }}&output=json&limit=5"

  # 5. Homoglyph detection — lookalike brands (paypa1, g00gle, etc.)
  - id: homoglyph_check
    type: transform
    with:
      compute:
        brand_match_found: "matchLookalike(hostname_normalized, brand_list)"
        suspicious_tld:    "hostname.endsWith('.xyz') || endsWith('.tk') ..."

  # 6. GPT-4o-mini — classify, MITRE T1566.002, containment guidance
  - id: gpt_analysis
    type: llm.analyze
    with:
      model:       gpt-4o-mini
      json_output: true
      prompt:      "Classify URL. Return JSON: classification, confidence, reasoning, mitre_techniques[], phishing_signals[], legitimate_signals[]"

  # 7. Score 0–100 (URLhaus:35, young domain:20, homoglyph:20, IP host:10, cert:10, LLM:30)
  - id: severity_score
    type: transform
    with:
      compute:
        score:    "clamp(urlhaus_pts + young_domain_pts + homoglyph_pts + ip_pts + cert_pts + llm_pts, 0, 100)"
        severity: "score>=70?critical : score>=40?high : score>=20?medium : low"

  # 8. Containment: block at proxy/DNS, notify user, quarantine inbox
  - id: containment_recommendation
    type: output
    with:
      value:
        classification: "{{ steps.gpt_analysis.output.parsed.classification }}"
        score:           "{{ steps.severity_score.output.score }}"
        severity:        "{{ steps.severity_score.output.severity }}"
        containment_actions:
          block_at_proxy:    "{{ steps.url_normalize.output.domain }}"
          block_at_dns:      "{{ steps.url_normalize.output.hostname }}"
          notify_user:       "Alert user who clicked this URL"
          quarantine_emails: "Search inbox for domain {{ steps.url_normalize.output.domain }}"

Run Demo

Submit a suspicious URL. The engine checks domain age, URLhaus, TLS certs, and homoglyph patterns — then GPT-4o-mini maps it to MITRE ATT&CK and recommends containment.

LIVE Multi-stage chain trigger: alert_triggered (EDR)

Ransomware Containment & IR Chain

Full incident response pipeline with conditional branching: parses EDR alert, looks up hash in MalwareBazaar, scores severity 0–100 with GPT-4o-mini, then branches — high-severity hosts get network-isolated, user-suspended, and volume-snapshotted. All paths collect forensic artifacts, extract IOCs, generate an exec-ready MITRE ATT&CK summary, post to Slack, and open a P1 ticket. 13 steps across 5 stages.

13 steps · 5 stages · ~12s runtime · MalwareBazaar + GPT-4o-mini
Stage 1
Detection & Enrichment
alert_parse hash_reputation host_context
Stage 2
Triage Decision
severity_score containment_decision
≥70 → isolate<70 → skip
Stage 3
Containment (score ≥ 70)
isolate_host disable_user snapshot_volumes
Stage 4
Forensics
collect_artifacts ioc_extraction
Stage 5
Notify & Report
incident_summary slack_notify ticket_create
ransomware-ir-chain.yaml
name: Ransomware IR Chain
trigger: alert_triggered
inputs:
  - name: host_id
  - name: user_id
  - name: sha256
  - name: process_name
  - name: behavior_flags

steps:

  # ── Stage 1: Detection & Enrichment ─────────────────────────────
  - id: alert_parse
    type: transform      # extract fields, score behavior indicators

  - id: hash_reputation
    type: http.post      # MalwareBazaar lookup (no API key)
    on_failure: continue

  - id: host_context
    type: transform      # prod/exec/dc = critical, dev = standard

  # ── Stage 2: Triage Decision ─────────────────────────────────────
  - id: severity_score
    type: llm.analyze    # GPT-4o-mini scores 0–100, MITRE reasoning
    with:
      model: gpt-4o-mini
      json_output: true

  - id: containment_decision
    type: conditional   # BRANCH: score >= 70 → isolate, else monitor
    with:
      if: "steps.severity_score.output.parsed.score >= 70"

  # ── Stage 3: Containment (only if score >= 70) ──────────────────
  - id: isolate_host
    type: transform      # simulated CrowdStrike /contain API
    if: "steps.containment_decision.output.result == true"

  - id: disable_user
    type: transform      # simulated Okta deactivate
    if: "steps.containment_decision.output.result == true"

  - id: snapshot_volumes
    type: transform      # simulated AWS EBS snapshot for forensics
    if: "steps.containment_decision.output.result == true"

  # ── Stage 4: Forensics Collection ───────────────────────────────
  - id: collect_artifacts
    type: transform      # assemble process tree, net conns, modified files

  - id: ioc_extraction
    type: llm.analyze    # IPs, domains, hashes, mutex, dropped files
    with:
      model: gpt-4o-mini
      json_output: true

  # ── Stage 5: Notification & Reporting ───────────────────────────
  - id: incident_summary
    type: llm.analyze    # exec-ready summary, T1486 + T1490 ATT&CK map
    with:
      model: gpt-4o-mini
      json_output: true

  - id: slack_notify
    type: transform      # mock webhook → #security-incidents

  - id: ticket_create
    type: output         # P1 Jira ticket with full IR dossier

Run Demo

Submit a canned EDR alert. The engine runs all 5 stages — watch the containment decision branch in real time based on the severity score.

LIVE Cloud trigger: alert_triggered (cloud monitoring / scheduled)

Cloud Storage Exposure Hunter

Detects publicly exposed S3 and GCS buckets: probes for public listing, samples up to 50 objects, flags sensitive patterns (SQL dumps, .env files, credentials, PEM keys, customer CSVs), HEAD-checks the first hit for content type, classifies sensitivity and blast radius with GPT-4o-mini, recommends containment (block / rotate-and-quarantine / monitor), and maps to MITRE T1530 + T1078. 10 steps, ~15s end-to-end.

10 steps · ~15s runtime · S3 + GCS + GPT-4o-mini
cloud-storage-exposure-hunter.yaml
name: Cloud Storage Exposure Hunter
trigger: alert_triggered
inputs:
  - name: bucket_url
    description: "s3://bucket, gs://bucket, or HTTPS URL"

steps:

  # 1. Normalize URL → provider + bucket_name
  - id: normalize_bucket
    type: transform

  # 2. Probe public listing (S3 list-type=2 / GCS JSON)
  - id: probe_public_listing
    type: http.get
    on_failure: continue

  # 3. Count total exposed objects, sample 20 keys
  - id: count_objects
    type: transform

  # 4. Flag sensitive patterns (.sql, .env, .pem, credentials, prod)
  - id: flag_sensitive_patterns
    type: transform

  # 5. HEAD first sensitive key → Content-Type + size
  - id: head_sample_object
    type: http.get
    on_failure: continue

  # 6. GPT-4o-mini sensitivity: score 0-100, data_classes, blast_radius
  - id: llm_classify_sensitivity
    type: llm.analyze
    with:
      model: gpt-4o-mini
      json_output: true

  # 7. GPT-4o-mini action: block-public-access | rotate-keys-and-quarantine | monitor
  - id: llm_recommend_action
    type: llm.analyze
    with:
      model: gpt-4o-mini
      json_output: true

  # 8. MITRE: T1530 always; T1078 if credentials exposed
  - id: mitre_mapping
    type: transform

  # 9. Severity: ≥80 critical, 50-79 high, 20-49 medium, <20 low
  - id: severity_calc
    type: transform

  # 10. Output verdict panel
  - id: output
    type: output
Live Demo Uses public S3/GCS endpoints — no credentials required
SAMPLES:
LIVE trigger: alert_triggered (brand monitoring / scheduled)

Brand Impersonation & Typosquat Hunter

Brand-protection pipeline: pulls all TLS certs containing your brand token from crt.sh, dedupes candidates, scores each by Levenshtein distance and homoglyph visual similarity, checks registration age via RDAP (flags domains <14 days), queries URLhaus for known-malicious matches, classifies with GPT-4o-mini (MITRE T1583.001), and emits a ranked verdict panel with recommended actions (file UDRP / monitor / report / ignore). 10 steps, ~15s end-to-end.

10 steps · ~15s runtime · crt.sh + RDAP + URLhaus + GPT-4o-mini
brand-impersonation-hunter.yaml
name: Brand Impersonation & Typosquat Hunter
trigger: alert_triggered
inputs:
  - name: brand_domain
    description: "Brand domain to protect (e.g. stripe.com)"

steps:

  # 1. Derive brand token from domain (e.g. 'stripe' from 'stripe.com')
  - id: extract_brand
    type: regex.extract
    with:
      input:   "{{ inputs.brand_domain }}"
      pattern: "^([^.]+)"

  # 2. crt.sh — all certs issued containing brand token as substring
  - id: crt_lookup
    type: http.get
    on_failure: continue
    with:
      url: "https://crt.sh/?q=%25{{ steps.extract_brand.output.brand_token }}%25&output=json&deduplicate=Y"

  # 3. Dedupe + filter legit subdomains from brand domain itself
  - id: candidates_filter
    type: transform
    with:
      compute:
        candidates_raw: "dedupe(filter(crt_results, not(isLegitSubdomain)))"

  # 4. Levenshtein + homoglyph score (0↔g, 1↔l, rn↔m, etc.)
  - id: homoglyph_score
    type: transform
    with:
      compute:
        scored_candidates: "sortDesc(map(candidates, scoreBySimilarity))"

  # 5. RDAP — registration date + registrar for top candidate
  - id: rdap_top
    type: http.get
    on_failure: continue
    with:
      url: "https://rdap.org/domain/{{ steps.homoglyph_score.output.top_candidate }}"

  # 6. URLhaus — known-malicious check for top candidate
  - id: urlhaus_top
    type: http.post
    on_failure: continue
    with:
      url: "https://urlhaus-api.abuse.ch/v1/host/"
      body:
        host: "{{ steps.homoglyph_score.output.top_candidate }}"

  # 7. GPT-4o-mini — classify each as likely-typosquat | suspicious-lookalike | benign-coincidence
  - id: llm_classify
    type: llm.analyze
    with:
      model:       gpt-4o-mini
      json_output: true
      prompt:      "Classify candidates. MITRE T1583.001. Return JSON: overall_risk, overall_score, summary, classifications, top_offenders[], brand_protection_actions[]"

  # 8–10. Score, severity, output verdict panel
  - id: brand_verdict
    type: output
    with:
      value:
        score:            "{{ steps.risk_score.output.score }}"
        severity:         "{{ steps.risk_score.output.severity }}"
        total_candidates: "{{ steps.candidates_filter.output.candidates_count }}"
        top_offenders:    "{{ steps.llm_classify.output.parsed.top_offenders }}"
        classifications:  "{{ steps.llm_classify.output.parsed.classifications }}"
        recommended_actions: "file UDRP | monitor | report | ignore"

Run Demo

Enter a brand domain. The engine scans certificate transparency logs, scores every look-alike by homoglyph similarity, checks registration age, and classifies each with GPT-4o-mini. Real typosquats surface in ~15 seconds.

Run these on your own data

Connect your own triggers and run any workflow against real events. Plans start at $299/mo.

See plans →
DESIGN PARTNERS

Get Early Access

We're onboarding design partners now — 7 live workflows, more shipping weekly. Drop your email and we'll reach out with a spot.

Request a Workflow

Want a workflow we don't have yet?

Tell us what alert is eating your week. Every submission goes directly to the founder's inbox — and the highest-signal ones ship next.

Got it. You're on the list.

Check your inbox — confirmation on the way.