ThresholdIQ has two distinct layers with a clear security boundary between them:
| Component | Implementation |
|---|---|
| File reading | FileReader API (browser-native, no uploads to any server) |
| Data parsing | PapaParse (CSV), SheetJS (Excel), JSON.parse — all self-hosted |
| ML detection | 9 detection methods running in Web Workers (background threads in browser) |
| Visualization | Chart.js (client-side rendering) |
| PDF export | jsPDF + autoTable (client-side PDF generation, downloads locally) |
| Local storage | Optional — stores session token and preferences on device only, requires consent |
| Component | Implementation |
|---|---|
| API server | Cloudflare Worker (edge compute, no persistent server) |
| Data store | Cloudflare Workers KV (key-value store for account records) |
| Authentication | Email-based magic-link OTP (no passwords stored) |
| Payments | Stripe Checkout + Billing Portal (card data handled entirely by Stripe) |
| Email delivery | Zoho Mail API (OTP codes and alert notifications) |
Key point: The security boundary is clear — your data files stay in the browser, your account info (email + subscription) lives on the server. These two layers do not share data.
Verification: IT Security can confirm zero file data transmission by monitoring the Network tab (F12) during file upload and detection runs. You will see only static asset requests and API calls to /api/check-status and /api/track-run — no file content payloads.
ThresholdIQ uses passwordless email-based authentication with the following controls:
| Control | Implementation |
|---|---|
| OTP generation | 6-digit code from crypto.getRandomValues() (cryptographically secure random) |
| OTP expiry | 10 minutes (auto-deleted from KV after expiry) |
| OTP attempt limit | 3 incorrect attempts — code is invalidated, user must request a new one |
| Session tokens | HMAC-SHA256 signed (customerId.timestamp.signature), verified on every API request |
| Session expiry | 7 days (stateless — not stored server-side, validated via signature) |
| No passwords | No password database exists. Authentication is tied to email access only. |
All sensitive endpoints are rate-limited per IP address to prevent brute-force and abuse:
| Endpoint | Limit | Window |
|---|---|---|
OTP request (/api/auth/email) | 10 requests | 15 minutes |
OTP verification (/api/auth/verify-otp) | 10 attempts | 15 minutes |
Checkout (/api/create-checkout) | 5 attempts | 1 hour |
AI chatbot (/api/chat) | 20 messages | 1 hour |
Alert emails (/api/send-alert-email) | 10 emails | 1 hour |
Config (/api/config) | 30 requests | 1 minute |
Rate limit counters are stored in Cloudflare KV with automatic TTL expiry. No persistent IP address logs are kept.
/api/* endpoints reject requests unless the Origin or Referer header matches thresholdiq.app. Direct access to the Worker URL is blocked.Authorization header._headers file.Account data is stored in Cloudflare Workers KV. Here is the complete list of what is stored:
| Data | Storage location | Retention |
|---|---|---|
| Email address | KV (plaintext + SHA-256 hash index) | Until account deletion |
| Customer ID (UUID) | KV | Until account deletion |
| Subscription tier and status | KV | Until account deletion |
| Stripe customer ID and subscription ID | KV (IDs only — no card data) | Until subscription ends |
| Usage counters (runs this month) | KV | Monthly reset |
| OTP codes | KV | 10 minutes (auto-deleted) |
| Rate limit counters | KV | 15 min – 1 hour (auto-deleted) |
What is NOT stored server-side: No passwords, no credit card numbers, no file contents, no detection results, no column names, no threshold configurations, no raw data of any kind.
| Service | Purpose | Data shared |
|---|---|---|
| Cloudflare (Workers, KV, Pages) | Hosting, API, data storage | Account data, email, IP addresses |
| Stripe | Payment processing | Email address. Card data collected directly by Stripe — never touches our servers. |
| Zoho Mail | Transactional email delivery | Recipient email, email content (OTP codes, alert notifications) |
| Cloudflare Workers AI | In-app help chatbot | Chat messages (not stored after processing) |
| Google Analytics | Anonymised usage analytics | Page views, session data (anonymised IP) |
| Microsoft Clarity | Usability heatmaps | Anonymised session recordings (no PII) |
All JavaScript libraries are self-hosted within thresholdiq.app. No external CDN requests are required for core functionality.
| Library | Licence | Purpose |
|---|---|---|
| Chart.js | MIT | Timeline and distribution charts |
| PapaParse | MIT | CSV file parsing |
| SheetJS | Apache 2.0 | Excel file parsing |
| jsPDF + autoTable | MIT | Client-side PDF report generation |
| simple-statistics | ISC | Statistical computations for ML detection |
| isolation-forest | MIT | Multivariate outlier detection |
| Risk category | Risk level | Mitigation |
|---|---|---|
| Data exfiltration (file contents) | NONE | File data never leaves the browser. Verifiable via Network tab. |
| Account data breach | LOW | Only email + subscription IDs stored. No passwords, no card data. Cloudflare KV encrypted at rest. |
| Session hijacking | LOW | HMAC-SHA256 tokens, 7-day expiry, HTTPS-only transport, origin validation. |
| Brute-force login | LOW | 3-attempt OTP lockout + IP rate limiting (10 requests / 15 min). |
| Man-in-the-middle | LOW | TLS 1.3, HSTS preload, strict CSP headers. |
| Webhook spoofing | LOW | Stripe signatures verified with HMAC-SHA256 + timing-safe comparison + 5-min replay window. |
| Malicious code injection | LOW | Content-Security-Policy restricts script sources. All libraries self-hosted. |
Uploaded file data never leaves the user's browser, inherently satisfying data residency requirements. Account data (email, subscription status) is stored on Cloudflare's global edge network and may be replicated across regions. Payment processing is handled by Stripe (US-based). See our Privacy Policy for full details on international transfers.
https://thresholdiq.app (application + static assets)https://worker.vigneshj.workers.dev (backend API, proxied via thresholdiq.app/api/*)https://js.stripe.com and https://api.stripe.com (checkout and billing portal)zoho.com.au is not required — emails are sent server-side, not from the user's browserfonts.googleapis.com and fonts.gstatic.com (UI fonts)www.googletagmanager.com, www.google-analytics.com (analytics — can be blocked without affecting functionality)/api/track-run (run counter) and /api/check-status (tier check) — no file payloads.Email: support@thresholdiq.app
For responsible disclosure of security vulnerabilities, please email the same address with subject line "Security Disclosure".