Skip to main content

Overview

PensionPortal.ai uses Cloudflare as its CDN, WAF, and DNS layer in front of Vercel. All traffic to *.pensionportal.ai passes through Cloudflare before reaching Vercel’s edge network. This provides DDoS protection, web application firewall rules, rate limiting, and TLS termination.

DNS Records

Configure the following records in Cloudflare Dashboard → DNS → Records for pensionportal.ai.
TypeNameValueProxy StatusPurpose
CNAMEwwwcname.vercel-dns.comProxiedMarketing site
CNAMEappcname.vercel-dns.comProxiedApplication portal
CNAMEdocscname.vercel-dns.comProxiedMintlify documentation
CNAME*cname.vercel-dns.comProxiedWildcard coverage
TXT@v=spf1 include:_spf.resend.com ~allDNS onlyEmail SPF (Resend)
TXTresend._domainkeyDKIM value from Resend DashboardDNS onlyEmail DKIM
TXT_dmarcv=DMARC1; p=quarantine; rua=mailto:dmarc@pensionportal.aiDNS onlyDMARC policy
MX@mx1.improvmx.com (priority 10), mx2.improvmx.com (priority 20)DNS onlyEmail routing
Email records (SPF, DKIM, DMARC, MX) must be set to DNS only (grey cloud). Proxying these record types through Cloudflare would break email delivery and DKIM signature validation.
After adding or modifying DKIM and DMARC records, allow up to 48 hours for DNS propagation before running DMARC verification. Validate with dig TXT _dmarc.pensionportal.ai and a DMARC checker tool.

TLS Configuration

Configure in Cloudflare Dashboard → SSL/TLS.
SettingValueNotes
SSL ModeFull (Strict)Vercel certificates are verified end-to-end; rejects self-signed certs
Minimum TLS VersionTLS 1.2 (minimum)Recommend TLS 1.3 only for DORA compliance
HSTSEnabledmax-age=31536000; includeSubDomains; preload
CertificateCloudflare Universal SSL + Vercel Edge CertificateBoth auto-renewed
SSL Mode must be Full (Strict), never Flexible. Flexible mode encrypts only the Cloudflare-to-browser connection, leaving the Cloudflare-to-Vercel leg unencrypted. This would violate GDPR Article 32 and DORA technical security requirements for a regulated financial application.

HSTS Configuration

Enable HSTS in Cloudflare Dashboard → SSL/TLS → Edge Certificates → HTTP Strict Transport Security (HSTS):
Max Age: 12 months (31536000 seconds)
Include Subdomains: ON
Preload: ON
No-Sniff Header: ON
Once HSTS with preload is submitted to the HSTS preload list, it is very difficult to reverse. Ensure all subdomains serve valid HTTPS before enabling preload. Confirm with the team before enabling.

WAF Configuration

Configure in Cloudflare Dashboard → Security → WAF.

Managed Rulesets

Enable the following managed rulesets under WAF → Managed Rules:
RulesetStatusNotes
Cloudflare Managed RulesetONCovers common web exploits
Cloudflare OWASP Core RulesetONOWASP Top 10 protections
Cloudflare Exposed Credentials CheckONDetects use of known breached credentials

Custom WAF Rules

Create the following rules in Security → WAF → Custom Rules: Rule 1 — Geo-restrict regulated data endpoints This rule challenges non-EU/non-Irish traffic attempting to access regulated pension data APIs. PensionPortal.ai operates under IORP II, which is an Irish/EU regulatory framework.
(ip.geoip.continent ne "EU" and ip.geoip.country ne "IE"
 and http.request.uri.path matches "^/api/(schemes|members|employers|compliance).*")

Action: Challenge (Managed CAPTCHA)
Disable or modify this rule if expanding to non-EU markets (Wave 2). Ensure legal review of data residency obligations before disabling geo-restriction for any regulated endpoint.
Rule 2 — Protect RAG ingest endpoint The RAG ingest endpoint triggers AI document processing and is not intended for public access. Block all traffic except from known infrastructure IPs.
(http.request.uri.path matches "^/api/rag/ingest.*")

Action: Block (allowlist known IPs via IP Lists)
Create an IP List in Cloudflare → Manage Account → Configurations → Lists, and reference it in the rule to permit your CI/admin IPs. Rule 3 — Block common exploit patterns
(http.request.uri.query contains "../"
 or http.request.uri.query contains "UNION SELECT")

Action: Block
These custom WAF rules supplement, but do not replace, secure server-side input validation. The application must validate and sanitize all user input regardless of WAF rules — WAF rules can be bypassed by sophisticated attackers and should be treated as defence-in-depth.

Rate Limiting Rules

Configure in Cloudflare Dashboard → Security → WAF → Rate Limiting Rules.
Rule NamePath PatternThresholdPeriodAction
Login Rate Limit/api/auth/callback/credentials10 requests1 minuteBlock for 10 minutes
AI Chat Rate Limit/api/ai/chat30 requests1 minuteThrottle
API General Rate Limit/api/*500 requests1 minuteThrottle
RAG Ingest Protection/api/rag/ingest5 requests1 hourBlock
The login rate limit (10 req/min) is intentionally strict to prevent credential stuffing attacks against trustee accounts. Legitimate users should not approach this threshold during normal use. If users report false positives, investigate before raising the limit.

Bot Protection

Configure in Cloudflare Dashboard → Security → Bots.
SettingValueNotes
Bot Fight ModeONBlocks known bad bots
Super Bot Fight Mode (Pro+)Block definitely automated trafficRequires Pro plan or higher
Browser Integrity CheckON for /dashboard/* pathsValidates browser fingerprint
Challenge Passage30 minutesTime before re-challenging solved CAPTCHA
Super Bot Fight Mode may block legitimate API clients such as monitoring services (e.g., BetterUptime). Allowlist known monitoring IPs or user-agent strings in the Cloudflare firewall before enabling.

Zero Trust Configuration Plan

Cloudflare Zero Trust (formerly Cloudflare Access) provides identity-aware access control for sensitive admin paths, replacing IP-allowlisting with company identity authentication. Target state (future hardening):
  1. Create a Cloudflare Access application scoped to app.pensionportal.ai/admin/*
  2. Require authentication via Cloudflare Access + company email (Google Workspace or Azure AD IdP)
  3. Enable device posture checks — allow access only from managed, MDM-enrolled devices
  4. Log all access events to Cloudflare SIEM / Logpush (forward to your SIEM or audit log store)
  5. Conduct weekly access reviews — security lead reviews active users and revokes stale access
Zero Trust configuration requires a Cloudflare Zero Trust plan (free tier available for small teams). Review Cloudflare Access documentation before implementing.

Admin Route Protection — Current State

Until Zero Trust is fully configured, the following interim controls apply:
  • No dedicated /admin/* URL path exists. SuperAdmin capabilities are not exposed via a separate URL prefix.
  • Admin users are identified by role in the JWT, not by URL path. The SuperAdmin role is stored in the database and reflected in the session token.
  • All /api/* routes perform server-side role checks using the session JWT before executing privileged operations.
Role-based access in the JWT is only as secure as the AUTH_SECRET used to sign tokens. Ensure AUTH_SECRET is unique per environment, never committed to source control, and rotated if ever exposed. See the Vercel Deployment Guide for secret generation instructions.
Recommended next step: Implement a dedicated /admin route tree protected by both JWT role check and Cloudflare Access, providing defence-in-depth for the highest-privilege operations.

Performance Settings

Configure in Cloudflare Dashboard → Speed → Optimization and Caching.
SettingValueNotes
Auto Minify — HTMLONReduces HTML payload size
Auto Minify — CSSONReduces CSS payload size
Auto Minify — JavaScriptONReduces JS payload size
Brotli CompressionONMore efficient than gzip for modern browsers
HTTP/3 with QUICONReduces latency on unreliable connections
Rocket LoaderOFFIncompatible with Next.js hydration — do not enable

Cache Rules

Create a Cache Rule in Cloudflare Dashboard → Caching → Cache Rules: Rule: Cache Next.js static assets at edge
If URI path matches: ^/_next/static/.*
Cache TTL: 1 year (31536000 seconds)
Browser TTL: 1 year
Edge TTL: 1 year
Cache Status: Cache Everything
Next.js content-hashes all files in /_next/static/, making long-lived caching safe — stale files are never served because filenames change with each build.
Do not cache /api/* paths or /dashboard/* paths at the Cloudflare edge. These routes return user-specific or real-time data. Vercel handles caching for these routes via the Next.js cache headers.

Analytics and Monitoring

FeatureTargetNotes
Cloudflare AnalyticsAll zonesTraffic, bandwidth, threat insights
Web Analytics (privacy-preserving)www.pensionportal.aiNo cookies, GDPR-compliant, no consent banner required
Security EventsReview weeklyCheck for blocked requests, unusual geo patterns
Under Attack ModeActivate during active DDoS onlyJS challenge for all visitors; disables normal access
Web Analytics setup: Add the Cloudflare Web Analytics script to the marketing site (www.pensionportal.ai). This script does not use cookies and does not require a GDPR consent banner, making it suitable for a regulated financial platform.
Under Attack Mode should only be activated during an active, confirmed DDoS event. Enabling it outside of an incident will challenge all legitimate users — including pension trustees — with a browser integrity check, causing significant friction. Coordinate activation with the security lead and document the decision in the incident log.
Security Events review checklist (weekly):
  • Check for any WAF rule triggers on /api/auth/* — spikes may indicate credential stuffing
  • Review blocked geo-restriction hits on regulated endpoints
  • Check rate limit trigger counts — a significant increase may indicate automated probing
  • Review any manual Block actions and confirm they remain appropriate