Security by design. Not by bolt-on.
Footfall is built with defense in depth — from bcrypt hashing and tenant isolation to CSP headers and container hardening. Every layer is documented, testable, and turned on by default.
bcrypt Hashing
password storage
Tenant Isolation
business_id scoped
CSRF Tokens
all POST forms
Rate Limiting
per-route rules
SSRF Protection
public IPs only
Container Hardening
pinned images
Secret Validation
required at boot
Vulnerability Reporting
security@ email
Authentication & Session Management
The Challenge
Guest WiFi platforms handle PII, RADIUS credentials, and integration secrets. Weak auth or leaked sessions put every tenant at risk.
The Mechanism
Footfall uses bcrypt password hashing, enforces account lockout after 5 failed attempts, and issues HttpOnly / Secure / SameSite=Lax session cookies. The app refuses to start without a strong SECRET_KEY.
What it does
- bcrypt password hashing
- Account lockout with 15-minute window
- HttpOnly / Secure / SameSite=Lax cookies
- SESSION_LIFETIME_MINUTES based expiry
- SECRET_KEY required at startup
Input Validation & Output Encoding
The Challenge
Captive portals accept user input. Campaigns render templates. Custom CSS runs on the page. Every one of these is an injection vector if not handled.
The Mechanism
CSRF tokens protect POST forms. Campaign templates run in a sandboxed Jinja2 environment. Custom CSS is parsed and normalized. Redirect URLs are validated, and search terms escape SQL LIKE wildcards.
What it does
- CSRF tokens on all forms
- Sandboxed campaign templates
- cssutils parsing for custom CSS
- Validated next / redirect URLs
- SQL LIKE wildcard escaping
Rate Limiting & Abuse Prevention
The Challenge
Login, OTP, voucher, and API endpoints are attractive targets for brute-force and abuse. A platform without rate limits is an easy target.
The Mechanism
Flask-Limiter applies default limits to public routes and stricter limits to auth, registration, OTP, buy/redeem, and API endpoints. The key function respects X-Forwarded-For behind a trusted proxy.
What it does
- 200/day default public limit
- 10/min auth limits
- 5/min OTP request limits
- 10/min portal buy/redeem
- X-Forwarded-For aware keying
Transport Security & Headers
The Challenge
Without strict transport headers and CSP, even a well-coded app can be compromised by clickjacking, MIME sniffing, or malicious inline scripts.
The Mechanism
Flask-Talisman sets Content-Security-Policy with nonces, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy, and a restrictive Permissions-Policy. HSTS is added in non-test environments.
What it does
- CSP with nonces
- X-Frame-Options: DENY
- X-Content-Type-Options: nosniff
- Strict Referrer-Policy
- HSTS in production
Integration & Outbound Request Safety
The Challenge
Webhook and CRM integrations accept user-supplied URLs. Without validation, they can become SSRF tunnels into internal services.
The Mechanism
Webhook, Zapier, Salesforce, and Zoho integrations validate that URLs are public http(s) endpoints and do not resolve to private or reserved IP ranges. Outbound requests time out after 10 seconds.
What it does
- Public http(s) URL validation
- Private/reserved IP rejection
- 10-second outbound timeout
- SSRF prevention on webhooks
- Timeout on all outbound requests
Container & Infrastructure Hardening
The Challenge
Docker images and compose files often ship with weak defaults, outdated base images, or leaked secrets. Production deployments need hardening by default.
The Mechanism
.dockerignore excludes .env, .git, venv, and tests. FreeRADIUS is pinned to a specific version. Redis requires a password. RADIUS refuses to start if RADIUS_DEFAULT_SECRET is missing or still a placeholder.
What it does
- .dockerignore for secrets and cache
- Pinned FreeRADIUS 3.2.3
- Redis requirepass
- RADIUS secret validation
- No weak production fallbacks
Secrets & Vulnerability Reporting
The Challenge
Even the best controls fail if secrets are weak or reused. And when researchers find issues, there needs to be a clear, safe way to report them.
The Mechanism
A production secrets checklist covers SECRET_KEY, REDIS_PASSWORD, DB_PASSWORD, RADIUS_DEFAULT_SECRET, RADIUS_CLIENT_NET, and all integration credentials. Security issues can be reported to security@app.footfall.cloud.
What it does
- 48+ byte SECRET_KEY required
- Unique RADIUS_DEFAULT_SECRET
- Narrow RADIUS_CLIENT_NET CIDR
- OAuth and mail credential checklist
- security@app.footfall.co reporting