Skip to main content
Security posture · last updated 2026-06-22

Security is the product. Here's how we run it on ourselves.

This page documents how PhishFence handles your data, what we hold and don't hold, and the cryptographic and operational controls we run. For sub-processors, our DPA, and our compliance roadmap, see /trust. Updated whenever the posture changes.

Data we hold, and data we don't

We storeWe do not store
  • · Customer email address (account identifier)
  • · Hashed password
  • · Monitored domain names
  • · Lookalike scan results & risk scores
  • · DMARC aggregate reports (RUA)
  • · Screenshots of suspect domains
  • · Alert configurations & notification routing
  • · API token hashes (plaintext shown once at creation)
  • · Audit log of security-relevant events
  • · Billing metadata via Stripe (subscription IDs, plan)
  • · Message bodies or customer email contents
  • · End-user PII beyond what's required for the account
  • · DMARC forensic reports (RUF), opt-in only
  • · Payment card numbers (handled by Stripe)
  • · Plaintext passwords
  • · Plaintext API tokens after creation
  • · Browser cookies for third-party advertising
  • · Cross-site tracking pixels

Encryption

At restManaged PostgreSQL on Google Cloud SQL with disk encryption enabled. Passwords are bcrypt-hashed. API tokens are stored as keyed hashes; the plaintext is shown to the user once at creation and never persisted.
In transitTLS 1.2 or higher on every external endpoint. HSTS enforced with max-age=31536000; includeSubDomains; preload. HTTP requests upgraded via upgrade-insecure-requests CSP directive.
Inbound mailMTA-STS published at mta-sts.phishfence.io in enforce mode. Senders refuse to deliver mail to phishfence.io over non-TLS.
SecretsStored in Google Cloud Secret Manager and injected at runtime. Never committed to source control.

Authentication

MethodStatusNotes
Email + passwordLiveStrong-password policy with a common-password blocklist. Bcrypt hashed.
Magic-link loginLiveSingle-use token, short expiry.
Google OAuth loginLiveOIDC; standard Google sign-in.
Email verification on signupLiveRequired before sensitive actions.
Password resetLiveEmail-delivered single-use token. Reuse and brute force are rate-limited.
Session tokensLiveJWT in an HttpOnly, Secure, SameSite cookie with a rolling lifetime. Changing the password invalidates all prior tokens.
API tokensLiveKeyed-hashed at rest and rate-limited per token.

Enterprise authentication requirements (SSO, MFA policy)? Talk to us.

Authorization & tenant isolation

  • · Every dashboard and API endpoint scopes queries to the authenticated user, enforcing tenant isolation at the data layer.
  • · CSRF tokens enforced on every state-changing request (POST, PATCH, DELETE) via dedicated middleware.
  • · Rate limiting on authentication endpoints and on the public domain checker.
  • · Admin endpoints require an explicitly granted admin role.
  • · Team-based features (multi-user accounts) enforce both team membership and per-feature plan gates before granting access.

Application security

Content-Security-PolicyStrict CSP with default-src 'self', no unsafe-inline on script-src, frame-ancestors 'none', and object-src 'none'.
ClickjackingX-Frame-Options: DENY in addition to the CSP frame-ancestors.
MIME sniffingX-Content-Type-Options: nosniff.
Referrer policystrict-origin-when-cross-origin.
Permissions policyCamera, microphone, geolocation, payment, and other powerful APIs all blocked at the browser level.
Output encodingJinja2 autoescape enforced. User-supplied content rendered via standard template variables, never |safe.
Input validationPydantic models on every API endpoint, server-side validation on every form. Domain inputs canonicalized and length-capped before storage.
Web application firewallApplication-level WAF middleware that bans IPs exhibiting malicious request patterns.
Prompt injectionLLM-backed features treat all model outputs as untrusted content. Generated text is rendered, never executed, never used as a tool call.
DependenciesPinned versions, reviewed for known CVEs prior to deploy.

Operational security

  • · Hosting: Google Cloud Run for the web tier and Cloud SQL (PostgreSQL) for the data tier, in a US region.
  • · Backups: Automated, encrypted backups with point-in-time recovery.
  • · Error monitoring: Personally identifiable fields are scrubbed before transmission; message bodies and customer email contents are never sent.
  • · Email sending: Transactional only (account verification, password reset, alert notifications). DMARC enforced on phishfence.io's sending domain.
  • · Logs: Structured logs to Google Cloud Logging. Security-sensitive actions are recorded in a separate audit log.
  • · Deploys: All deploys go through CI with automated tests, type checks, and security scans. Production deploys are gated behind manual approval.

Incident response

  • · Affected customers will be notified within 72 hours of a confirmed incident affecting their data, mirroring the GDPR Article 33 timeline.
  • · Notification goes to the email address of record on the affected account, plus a public post-mortem if the incident is wide-scope.
  • · Detection inputs include error-monitoring alerts, logging metrics, abuse signals from the WAF, and customer reports to security@phishfence.io.
  • · For incident updates and service-level questions, email support@phishfence.io.

Account & data deletion

Account deletion is a self-service action from Settings → Delete account. Confirmation requires re-typing your account email. On confirmation, in a single database transaction we:

  1. Cancel any active Stripe subscription so billing stops immediately.
  2. Delete monitored domains and every alert, alert event, screenshot, and phishing report attached to them.
  3. Delete pending email verifications, password resets, feedback, API tokens, and team memberships.
  4. Remove the user identifier from retained audit-log entries (we keep the event records so a forensic trail survives the deletion).
  5. Hard-delete the user row itself.

Cached error context for the deleted user ages out on our error-monitoring provider's rolling window. Backups containing your data age out per our backup retention window.

Owners of teams with active members must transfer ownership or dissolve the team before deletion can proceed.

Report a vulnerability

Send vulnerability reports to security@phishfence.io. Our coordinates are also published per RFC 9116 at /.well-known/security.txt.

Please include reproduction steps, the affected endpoint or URL, and any proof-of-concept payload. We respond within one business day and aim to issue an initial fix or mitigation within 7 days for high-severity issues. We won't pursue legal action against researchers who follow standard responsible-disclosure norms.

Get in touch