Attack Mode
Protect your deployed applications from DDoS attacks and bot traffic with a built-in proof-of-work challenge system. No third-party CAPTCHA services, no external dependencies -- everything runs on your infrastructure.
Overview
Attack Mode is Temps's self-hosted alternative to Cloudflare's "Under Attack Mode." When enabled, every visitor must complete a proof-of-work (PoW) challenge before accessing your application. The challenge is solved automatically in the visitor's browser using a WebAssembly solver -- no user interaction required.
Key Features:
- Zero dependencies -- no third-party CAPTCHA services or API keys
- Automatic solving -- visitors see a brief checkpoint page while their browser solves the challenge (2-5 seconds)
- 24-hour sessions -- once verified, visitors can browse freely for 24 hours
- TLS fingerprinting -- sessions are tied to JA4 TLS fingerprints for stronger identity binding
- WASM-powered -- Rust compiled to WebAssembly for 30-50x faster solving than JavaScript
- Per-project control -- enable or disable per project from the dashboard, CLI, or API
When to use Attack Mode:
- Your application is under active DDoS attack
- You're seeing suspicious bot traffic patterns
- You want to protect a public-facing app during a critical event
- You need immediate protection without external service setup
When not to use it:
- For API endpoints consumed by other services (they can't solve PoW challenges)
- Permanently on production -- it adds latency for first-time visitors
- For applications that need to be crawled by search engines
How It Works
When a visitor requests a page on a project with Attack Mode enabled, the Temps proxy intercepts the request and runs through the following flow:
Challenge Flow
- Request arrives at the Pingora-based reverse proxy
- Session check -- the proxy looks up the visitor's JA4 TLS fingerprint (or IP address as fallback) in the
challenge_sessionstable - If valid session exists -- the request passes through to your application normally
- If no valid session -- the proxy returns a 403 response with an HTML challenge page
- Browser solves challenge -- the embedded WASM solver finds a nonce such that
SHA-256(challenge + nonce)has at least 20 leading zero bits (~1 million hash attempts, takes 2-5 seconds) - Solution submitted -- the browser POSTs the solution to
/api/_temps/captcha/verify - Server verifies -- the proxy recomputes the hash and checks the leading zero bits
- Session created -- a 24-hour session is stored in the database, keyed to the visitor's TLS fingerprint
- Page loads -- the browser redirects to the original URL
Attack Mode requires HTTPS. HTTP requests return a 426 Upgrade Required response because JA4 TLS fingerprinting -- used to identify visitors across requests -- is only available on TLS connections.
Proof-of-Work Details
The challenge uses SHA-256 hashing with a difficulty of 20 leading zero bits, which requires approximately 1 million hash attempts on average. The WASM solver processes this in 2-5 seconds on modern hardware.
- Name
Algorithm- Type
- SHA-256
- Description
The solver concatenates the challenge string with a nonce and computes
SHA-256(challenge + nonce). It increments the nonce until the hash has the required number of leading zero bits.
- Name
Difficulty- Type
- 20 bits
- Description
20 leading zero bits means the hash must start with at least 5 hex zeros (e.g.,
00000a3f...). This takes ~1M attempts on average -- enough to deter bots while remaining fast for browsers.
- Name
WASM Solver- Type
- Rust → WebAssembly
- Description
The solver is written in Rust and compiled to WebAssembly via
wasm-bindgen. It uses the optimizedsha2crate and is 30-50x faster than the JavaScript fallback. Progress callbacks update the UI every 10,000 iterations.
- Name
Session Duration- Type
- 24 hours
- Description
Once a challenge is solved, the session is valid for 24 hours. Sessions are keyed to the visitor's JA4 TLS fingerprint (or IP address if fingerprinting is unavailable). Disabling attack mode clears all active sessions.
- Name
JavaScript Fallback- Description
If the WASM module fails to load (older browsers, disabled WebAssembly), the challenge page falls back to a pure JavaScript solver. It's slower but functional.
Enabling Attack Mode
Attack Mode can be enabled from the dashboard, CLI, or API.
Via Dashboard
- Go to Projects and select your project
- Open Settings → Security
- Toggle Enable Attack Mode in the Attack Mode card
- Click Save Attack Mode Settings
When enabled, an orange banner appears on the project detail page:
Attack Mode is enabled for this project -- with a quick-access Disable button to turn it off immediately.
Via CLI
CLI Commands
# Enable attack mode on a project
bunx @temps-sdk/cli projects settings -p my-app --attack-mode
Via API
# Enable attack mode
curl -X PATCH "https://your-temps-instance.com/api/projects/{project_id}/settings" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"attack_mode": true}'
# Disable attack mode
curl -X PATCH "https://your-temps-instance.com/api/projects/{project_id}/settings" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"attack_mode": false}'
Per-Environment Override
Attack mode can also be toggled per environment (e.g., enable only for production, not staging):
- Go to Project Settings → Environments
- Select the environment (production, staging, preview)
- Open the Security card
- Toggle Attack Mode for that specific environment
Environment-level settings override project-level settings. If attack mode is disabled at the project level but enabled on a specific environment, that environment will still require the PoW challenge.
Security Headers
Temps automatically applies configurable HTTP security headers to all responses from your deployed applications. Headers can be configured at three levels: global, project, and environment.
Presets
Choose from built-in presets or configure headers individually:
- Name
Strict- Description
Maximum security. Restrictive Content-Security-Policy (self only),
X-Frame-Options: DENY,Referrer-Policy: no-referrer, disabled browser features via Permissions-Policy. Best for applications that don't embed third-party content.
- Name
Moderate- Description
Balanced security. Allows inline scripts with nonces,
X-Frame-Options: SAMEORIGIN,Referrer-Policy: strict-origin-when-cross-origin. Good default for most applications.
- Name
Permissive- Description
Development-friendly. Allows
unsafe-inlineandunsafe-evalin CSP, relaxed restrictions. Use for development or staging environments where strict CSP would interfere with debugging tools.
- Name
Custom- Description
Full manual control over each header. Set individual values for Content-Security-Policy, X-Frame-Options, HSTS, Referrer-Policy, Permissions-Policy, X-Content-Type-Options, and X-XSS-Protection.
- Name
Disabled- Description
No security headers applied by Temps. Use when your application handles its own security headers.
Headers Configured
| Header | Description |
|---|---|
Content-Security-Policy | Controls which resources the browser can load |
X-Frame-Options | Prevents clickjacking by controlling iframe embedding |
X-Content-Type-Options | Prevents MIME type sniffing (nosniff) |
X-XSS-Protection | Enables browser's built-in XSS filter |
Strict-Transport-Security | Forces HTTPS connections (HSTS) |
Referrer-Policy | Controls how much referrer information is sent |
Permissions-Policy | Restricts browser features (camera, microphone, etc.) |
Configuring Headers
Dashboard vs API
1. Global: Settings → Security → Security Headers
2. Project: Project Settings → Security → Security Headers
3. Environment: Project Settings → Environments → [env] → Security
IP Access Control
Control access to your Temps instance at the infrastructure level with IP-based allow and block lists. Rules are enforced at the proxy layer before requests reach your applications.
Block List
Block known bad actors by IP address or CIDR range:
- Block individual IPs (e.g.,
192.168.1.100) - Block entire subnets (e.g.,
10.0.0.0/8) - Add a reason for each rule for audit purposes
- Blocked requests receive a
403 Forbiddenresponse
Allow List
Restrict access to only trusted IPs:
- Allow specific office or VPN IPs
- Allow CIDR ranges for your infrastructure
- Useful for internal tools or staging environments
Configuring IP Rules
- Go to Settings → Security → IP Access Control
- Click Add Rule
- Enter the IP address or CIDR range
- Select Block or Allow
- Optionally add a reason
- Save -- rules take effect immediately
Via API
# Block an IP
curl -X POST ".../api/ip-access-control" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ip_address": "192.168.1.100",
"action": "block",
"reason": "Suspicious activity"
}'
# Check if an IP is blocked
curl ".../api/ip-access-control/check/192.168.1.100" \
-H "Authorization: Bearer YOUR_TOKEN"
IP access control uses PostgreSQL's native inet type with the <<= operator for efficient CIDR matching. Both individual IPs and subnet ranges are supported in a single rule.
Rate Limiting
Configure per-IP request rate limits to protect against abuse. Rate limiting is available at the global, project, and environment levels.
- Name
Max Requests Per Minute- Type
- number
- Description
Maximum number of requests allowed from a single IP per minute. Requests exceeding this limit receive a
429 Too Many Requestsresponse.
- Name
Max Requests Per Hour- Type
- number
- Description
Maximum number of requests allowed from a single IP per hour. Provides a secondary limit for sustained abuse.
- Name
Whitelist IPs- Type
- string[]
- Description
IP addresses or CIDR ranges that bypass rate limiting entirely. Useful for your own monitoring services, CI/CD pipelines, or trusted partners.
- Name
Blacklist IPs- Type
- string[]
- Description
IP addresses or CIDR ranges that are always blocked, regardless of rate limits. These IPs receive an immediate
403 Forbiddenresponse.
Configuring Rate Limits
Rate Limiting
1. Global: Settings → Security → Rate Limiting
2. Project: Project Settings → Security → Rate Limiting
3. Environment: Project Settings → Environments → [env] → Security
When rate limiting is configured at multiple levels, whitelist and blacklist IPs are additive (merged from all levels), while numeric limits use the most specific configuration (environment overrides project, project overrides global).
Vulnerability Scanning
Temps automatically scans your deployed Docker images for known vulnerabilities using Trivy, an open-source security scanner. Scans run daily at midnight UTC and can also be triggered manually.
What Gets Scanned
- OS packages (Alpine, Debian, Ubuntu, etc.) -- detects CVEs in system libraries
- Language packages (npm, pip, Go modules, etc.) -- detects CVEs in application dependencies
- Container configuration -- checks for security misconfigurations
Severity Levels
- Name
Critical- Description
Vulnerabilities that are trivially exploitable with severe impact (e.g., remote code execution without authentication). Fix immediately.
- Name
High- Description
Serious vulnerabilities that are exploitable with significant impact. Fix as soon as possible.
- Name
Medium- Description
Vulnerabilities that require specific conditions to exploit or have limited impact. Plan to fix in the next release cycle.
- Name
Low- Description
Minor vulnerabilities with minimal impact or very difficult to exploit. Fix when convenient.
Viewing Scan Results
- Go to Projects and select your project
- Vulnerability scan results appear in the project overview
- Each scan shows total count and breakdown by severity (critical, high, medium, low)
- Click into a scan to see individual CVEs with package names, installed versions, fixed versions, and CVSS scores
Triggering a Manual Scan
# Via API
curl -X POST "https://your-temps-instance.com/api/projects/{project_id}/scans" \
-H "Authorization: Bearer YOUR_TOKEN"
# View latest scan results
curl "https://your-temps-instance.com/api/projects/{project_id}/scans/latest" \
-H "Authorization: Bearer YOUR_TOKEN"
# View vulnerabilities for a specific scan
curl "https://your-temps-instance.com/api/projects/{project_id}/scans/{scan_id}/vulnerabilities" \
-H "Authorization: Bearer YOUR_TOKEN"
Vulnerability scanning requires Trivy to be available on the Temps server.
Temps will automatically use it if installed. Install Trivy with: curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
Configuration Inheritance
Security settings follow a three-level inheritance chain. More specific settings override less specific ones:
Global Settings → Project Settings → Environment Settings
(defaults) (overrides global) (overrides project)
- Name
Global Level- Description
Default settings applied to all projects. Configure in Settings → Security. These act as your baseline security posture.
- Name
Project Level- Description
Override global settings for a specific project. Configure in Project Settings → Security. Leave fields empty to inherit from global.
- Name
Environment Level- Description
Override project settings for a specific environment (production, staging, preview). Configure in Project Settings → Environments → Security. Useful for stricter production settings or relaxed staging settings.
What Inherits How
| Setting | Inheritance Behavior |
|---|---|
| Security headers preset | Child overrides parent (most specific wins) |
| Rate limit numbers | Child overrides parent |
| Rate limit whitelist IPs | Additive (merged across all levels) |
| Rate limit blacklist IPs | Additive (merged across all levels) |
| Attack mode | Can be set at project or environment level independently |
Next Steps
- Monitoring -- Monitor application health and resource usage
- Error Tracking -- Track and debug application errors
- Logs -- View application and deployment logs
- Architecture: Security -- Security architecture overview