All Updates
6 May 2026
Weekly Update — Week ending 6 May 2026
TL;DR
This week we shipped a comprehensive security hardening pass (2 critical XSS vulnerabilities fixed, webhook signature enforcement, OAuth nonces, SSRF guards, CSP nonces on all inline scripts), 15 new database indexes with full-text search support, per-tenant worker sharding for scale, a unified contact model merging Contacts/Prospects/Candidates into one record, campaign enrollment deduplication with safe_enroll() across all 6 paths, warmup duplicate send root-cause fix, JobAdder ATS integration, table column reduction across Pipeline/Contacts/Prospects, server-side ICP filtering with pagination, broadened CSV importer, and a new target role field on contacts.
Security Hardening
- 2 critical XSS vulnerabilities fixed — Cross-site scripting vectors in e-sign template rendering and workspace preset icons patched. Both required authenticated access but could execute arbitrary scripts.
- Webhook signature enforcement — All inbound telephony webhooks now reject unsigned requests. Prevents spoofed webhook payloads from triggering actions.
- OAuth state nonce — OAuth flows now include a cryptographic nonce in the state parameter, preventing CSRF attacks during the authorization callback.
- SSRF guard — Server-side request forgery protection blocks requests to internal/private IP ranges. Applies to all URL-fetching features (website scraping, research, enrichment).
- Legacy password reset blocked — Deprecated reset flow that bypassed email verification is now rejected outright.
- CSP nonces on all inline scripts — All 30 inline script blocks across the application now use Content Security Policy nonces, eliminating unsafe-inline for script sources.
Database & Performance
- 15 new indexes — Added indexes on tenant_id across companies, contacts, and jobs tables plus 10 compound indexes on campaign worker hot paths. Queries on large datasets are materially faster.
- Full-text search — GIN trigram indexes now power ILIKE searches across contact names, emails, and company names. Partial-match search is 10–50x faster at scale.
- Per-tenant worker sharding — Campaign sends, inbox sync, and reply processing can now run on dedicated per-tenant workers. Prevents one busy account from blocking others.
- Structured logging — All application logs now emit structured JSON with request IDs, tenant context, and timing data for faster debugging.
- Container hardening — Application runs as non-root user with optimised image layers. Worker processes auto-recycle after 500 requests to prevent memory leaks.
Unified Contact Model
- One person, one record — Contacts, Prospects, and Candidates are now the same underlying record. No more duplicate data across different views.
- Multi-role support — A single contact can be both a prospect (linked to an Ideal Client Profile) and a candidate (linked to an Ideal Candidate Profile) simultaneously.
- Shared history — Email logs, call transcripts, campaign enrolments, meetings, and notes are all on one record regardless of which view you access them from.
- Seamless promotion — Click “Add to Prospects” or “Add to Candidates” on any contact to flag them for that pipeline. No data migration needed.
Campaign & Warmup Reliability
- Warmup duplicate send fix — Root cause identified and resolved: emails were being re-sent when a later processing stage failed and rolled back the “sent” status. Now uses independent transaction phases with claim-before-send.
- Unified safe enrollment — All 6 enrollment paths (campaign detail, bulk, CSV import, hot list, pipeline, company contacts) now use a single shared function with email-level deduplication and blocklist/DNC checking.
- Variant lockdown — A/B/C variant configuration is locked after campaign activation. Prevents data corruption from enrollment reassignment. Pause/resume per-variant still works.
- Database dedup constraints — Unique indexes on campaign enrollments prevent duplicate entries at the database level, catching edge cases that application logic might miss.
- Campaign rate accuracy — Open, click, and reply rates now use sent count as denominator (not enrolled). Variant cards show a Sent column for clearer comparison.
Table UX Overhaul
- Pipeline columns 12 → 7 — Removed Priority, Status, Posted, and Link columns. Key data visible at a glance with filters available for deep dives.
- Contacts columns 11 → 7 — Removed Source, Ad Role, and Added columns. Email status shown as a coloured dot with hover legend.
- Prospects columns 13 → 9 — Same streamlining pattern. Bulk actions switched to pill-style progress indicators.
- Column picker on Candidates — Show/hide columns with a toggle menu. Hidden-by-default columns reduce visual clutter while remaining accessible.
- Edit contact company — Company field on the edit contact modal now uses autocomplete with your existing company list.
- Email status dot legend — Colour-coded dots (green/amber/red/grey) on the credit costs bar explain what each email verification status means.
ICP & CSV Improvements
- Server-side ICP filtering — ICP prospects converted from client-side row-hiding to server-side database queries with proper LIMIT/OFFSET pagination. Handles thousands of prospects without browser slowdown.
- Date range filters — From/to date inputs with quick-select buttons (Today, 7d, 30d, 90d) on ICP prospects and Prospects pages. URL-persisted so filters survive navigation.
- CSV importer broadened — Column mapping now recognises 25+ header variants plus regex fallback for non-standard headers. Import files from any CRM or job board export.
- Target role field — New field on contacts for tracking the vacancy being recruited for. Shown on prospects page, ICP prospects, and prospect detail. Accepted in CSV import.
- Bulk action auto-refresh — Pages reload automatically 2 seconds after any bulk action completes, showing updated data without manual refresh.
Scrape Reliability
- Background task migration — Scrape jobs moved from in-process threads to dedicated background tasks that survive deployments. 15-minute timeout prevents indefinite hangs.
- Stale job cleanup — Automated periodic task detects and cleans up scrape jobs that have been running longer than expected.
- AJAX submission — Starting a scrape no longer requires a page reload. Submit and watch progress update in real time.
- 60-second per-company timeout — Find Contacts operations time out after 60 seconds per company, preventing a single slow lookup from blocking the entire batch.
Integrations & ATS
- JobAdder ATS integration — Full 5-phase integration: OAuth connection, contact sync, job sync, candidate push, and activity logging. Connect from the Integrations page.
- SSL certificate fix — Resolved intermittent SSL handshake failures on outbound email delivery that were causing campaign sends to retry unnecessarily.
- Team invite OAuth fix — Fixed a bug where accepting a team invitation via OAuth would fail to link the new user to the inviting tenant.
Quality & Testing
- 848 automated tests passing — Comprehensive test suite covering all routes, models, and background tasks. Every deployment is verified against the full suite.
- 107-page smoke test — Every page in the app automatically tested for errors after each update, including background AJAX endpoint checks.
- Progress pill fixes — Fixed dismiss comparison (started_at), failed pills now persist correctly, bell notifications fire on completion, and pills no longer ghost-reappear after dismissal.
- BulkActionLog per-item details — All 5 bulk action handlers now log per-item results (name, status, email/phone found) for the Logs page.
- Meeting reminders — Automatic email reminders 24 hours and 1 hour before scheduled meetings to both contact and host. Bell notification with amber clock icon.