Documentation Index
Fetch the complete documentation index at: https://docs.verbex.ai/llms.txt
Use this file to discover all available pages before exploring further.
Verbex uses a Web Application Firewall (WAF) to protect platform APIs and services from common web threats and malicious traffic.
Organization-Specific Protection
- WAF rules are applied per organization to ensure isolated and customizable protection.
- Each organization can define its own WAF policy based on its security requirements.
Policy Modes
Organizations can configure their WAF policy in one of the following modes:
- Default Deny with Allow Rules
- All traffic is denied by default.
- Only explicitly allowed requests are permitted.
- Default Allow with Deny Rules
- All traffic is allowed by default.
- Only explicitly denied requests are blocked.
Quick Start
# Create WAF configuration (ALLOW mode - blocklist)curl -X POST /v1/waf/config \
-H "X-User-Org-Id: your-org-id" \
-H "Content-Type: application/json" \
-d '{
"default_policy": "ALLOW",
"status": "ACTIVE"
}'
2. Add IP Rules
# Block a malicious IPcurl -X POST /v1/waf/rules \
-H "X-User-Org-Id: your-org-id" \
-H "Content-Type: application/json" \
-d '{
"ip_address": "198.51.100.50",
"action": "BLOCK",
"reason": "Suspicious activity detected"
}'
3. Check IP Access
# Check if an IP should be blockedcurl -X POST /v1/waf/check \
-H "X-User-Org-Id: your-org-id" \
-H "Content-Type: application/json" \
-d '{"ip_address": "198.51.100.50"}'
Response:
{ "ip_address": "198.51.100.50", "is_blocked": true, "action": "BLOCK", "matched_rule": "rule-id-here"}
Core Concepts
Default Policy
| Policy | Mode | Behavior |
|---|
ALLOW | Blocklist | Allow all IPs by default, block specific threats |
DENY | Allowlist | Block all IPs by default, allow specific trusted IPs |
IP Types
| Type | Format | Example | Description |
|---|
EXACT | Single IP | 192.168.1.100 | Match one specific IP |
CIDR | IP Range | 192.168.1.0/24 | Match IP range (256 IPs) |
CIDR Notation
IP_ADDRESS / PREFIX_LENGTH
| CIDR | Subnet Mask | IP Range | Total IPs |
|---|
/32 | 255.255.255.255 | Single IP | 1 |
/24 | 255.255.255.0 | x.x.x.0 - x.x.x.255 | 256 |
/16 | 255.255.0.0 | x.x.0.0 - x.x.255.255 | 65,536 |
/8 | 255.0.0.0 | x.0.0.0 - x.255.255.255 | 16,777,216 |
Rule Priority (Specificity)
When multiple rules match, the most specific wins:
/32 (exact) > /24 > /16 > /8 (broadest)
Example:
- Rule 1:
BLOCK 10.0.0.0/8
- Rule 2:
ALLOW 10.1.2.3/32
Result: IP 10.1.2.3 is ALLOWED (/32 beats /8)
WAF Status
| Status | Behavior |
|---|
ACTIVE | WAF rules are enforced |
INACTIVE | All IPs allowed (bypass mode for troubleshooting) |
API Reference
Endpoints
| Endpoint | Method | Description |
|---|
/v1/waf/check | POST | Check if IP should be blocked |
/v1/waf/config | GET | Get WAF configuration |
/v1/waf/config | POST | Create WAF configuration |
/v1/waf/config | PUT | Update WAF configuration |
/v1/waf/rules | POST | Create a rule |
/v1/waf/rules/paginated | GET | List rules with pagination |
/v1/waf/rules/{ruleId} | GET | Get rule by ID |
/v1/waf/rules/{ruleId} | PUT | Update rule |
/v1/waf/rules/{ruleId} | DELETE | Delete rule |
/v1/waf/rules/activate-all | POST | Activate all rules |
/v1/waf/rules/deactivate-all | POST | Deactivate all rules |
/v1/waf/cache/{orgId} | DELETE | Clear cache |
/v1/waf/cache/{orgId}/sync | POST | Sync cache from database |
| Header | Required | Description |
|---|
X-User-Org-Id | Yes | Organization identifier |
X-User-ID | No | User ID for audit trail |
X-Client-IP | No | Client IP for auto-rule creation |
X-Trace-Id | No | Request correlation ID |
Data Models
WAF Configuration:
{
"org_id": "string",
"default_policy": "ALLOW | DENY",
"status": "ACTIVE | INACTIVE",
"created_at": "2026-02-17T10:00:00Z",
"updated_at": "2026-02-17T10:00:00Z"
}
IP Access Rule:
{
"id": "string",
"org_id": "string",
"ip_address": "192.168.1.100",
"ip_type": "EXACT | CIDR",
"action": "ALLOW | BLOCK",
"reason": "string",
"is_active": true,
"expires_at": "2026-03-17T00:00:00Z",
"notes": "string",
"created_at": "2026-02-17T10:00:00Z",
"updated_at": "2026-02-17T10:00:00Z"
}
IP Check Response:
{
"ip_address": "192.168.1.100",
"is_blocked": false,
"action": "ALLOW",
"matched_rule": "rule-id or null",
"default_policy": "ALLOW (if no rule matched)"
}
Configuration
Application Properties
waf:
enabled: true # Enable/disable WAF
default-policy: ALLOW # System-wide default
cache-ttl: PT1H # Redis cache TTL
max-rules-per-org: 1000 # Max rules per org
debug-logging: false # Verbose logging
negative-cache:
enabled: true # Cache "no rule" results
ttl: PT5M # Negative cache TTL
cache-warmup:
enabled: true # Preload on startup
delay: PT5S # Warmup delay
batch-size: 100 # Orgs per batch
Limits
| Resource | Limit |
|---|
| Rules per organization | 1,000 |
| Batch operations | 100 rules |
| Pagination max size | 100 items |
Usage Examples
Example 1: Blocklist Mode (Default: ALLOW)
Block specific threats while allowing all other traffic.
# 1. Configure ALLOW modecurl -X POST /v1/waf/config \
-H "X-User-Org-Id: acme-corp" \
-d '{"default_policy": "ALLOW", "status": "ACTIVE"}'# 2. Block attacker IPcurl -X POST /v1/waf/rules \
-H "X-User-Org-Id: acme-corp" \
-d '{"ip_address": "198.51.100.50", "action": "BLOCK", "reason": "Brute force"}'
Result:
| IP | Rule Match | Access |
|---|
203.0.113.10 | No rule → Default ALLOW | Allowed |
198.51.100.50 | BLOCK rule | Blocked |
Example 2: Allowlist Mode (Default: DENY)
Only allow specific trusted IPs.
# 1. Configure DENY mode (auto-creates rule for your IP)curl -X POST /v1/waf/config \
-H "X-User-Org-Id: acme-corp" \
-H "X-Client-IP: 203.0.113.10" \
-d '{"default_policy": "DENY", "status": "ACTIVE"}'# 2. Allow office networkcurl -X POST /v1/waf/rules \
-H "X-User-Org-Id: acme-corp" \
-d '{"ip_address": "192.168.1.0/24", "action": "ALLOW", "reason": "Office network"}'
Result:
| IP | Rule Match | Access |
|---|
203.0.113.10 | Auto-created ALLOW | Allowed |
192.168.1.50 | CIDR ALLOW | Allowed |
10.0.0.99 | No rule → Default DENY | Blocked |
Example 3: Temporary Contractor Access
# Create rule with expirationcurl -X POST /v1/waf/rules \
-H "X-User-Org-Id: acme-corp" \
-d '{
"ip_address": "45.67.89.100",
"action": "ALLOW",
"reason": "Contractor - Project Alpha",
"expires_at": "2026-03-17T00:00:00Z",
"notes": "Contract #CON-2026-042"
}'
Rule auto-expires and is cleaned up by hourly job.
Example 4: CIDR with Exception
Block a range but allow specific IP within it.
# Block suspicious rangecurl -X POST /v1/waf/rules \
-H "X-User-Org-Id: acme-corp" \
-d '{"ip_address": "198.51.100.0/24", "action": "BLOCK", "reason": "Malicious range"}'# Allow trusted partner in that rangecurl -X POST /v1/waf/rules \
-H "X-User-Org-Id: acme-corp" \
-d '{"ip_address": "198.51.100.75", "action": "ALLOW", "reason": "Trusted partner"}'
Result: 198.51.100.75 is ALLOWED (/32 beats /24)
Architecture
Multi-Tenant Design
WAF operates at the organization level with complete isolation.
flowchart TB
subgraph Platform["Platform"]
subgraph Org1["Organization A"]
WAF1["WAF Config + Rules"]
end
subgraph Org2["Organization B"]
WAF2["WAF Config + Rules"]
end
end
IP Check Flow
Redis Key Patterns
| Key | Type | Purpose |
|---|
waf:exact:{orgId} | Hash | Exact IP rules |
waf:cidr:{orgId} | Hash | CIDR rules |
waf:config:{orgId} | String | Default policy |
waf:nc:{orgId}:{ip} | String | Negative cache |
Storage
- MongoDB: Source of truth for config and rules
- Redis: High-performance cache layer
Response Times
| Scenario | Latency |
|---|
| Redis hit (exact/CIDR) | ~1ms |
| Redis hit (negative cache) | ~1ms |
| MongoDB fallback | ~15ms |
Negative Cache
Caches “no rule found” results to prevent repeated MongoDB queries.
Without negative cache: Every unknown IP → MongoDB query With negative cache: First query → MongoDB, subsequent → Redis (~93% faster)
Cache Invalidation
| Operation | Invalidation Scope |
|---|
| Create exact rule | Single IP negative cache |
| Create CIDR rule | All negative cache for org |
| Update policy | All negative cache for org |
| Sync cache | All cache for org |
Troubleshooting
Enable Debug Logging
Common Issues
| Issue | Solution |
|---|
| Rule not taking effect | Clear cache: DELETE /v1/waf/cache/{orgId} |
| Locked out after DENY mode | Auto-rule should be created; check with GET /v1/waf/rules |
| High latency | Check Redis connectivity; ensure cache warmup completed |
| Rules not expiring | Verify cleanup scheduler is running |
Bypass WAF for Troubleshooting
Set status to INACTIVE to allow all traffic:
curl -X PUT /v1/waf/config \
-H "X-User-Org-Id: your-org-id" \
-d '{"status": "INACTIVE"}'
Remember to re-enable after troubleshooting!
Safety Features
Auto-Rule Creation
When switching to DENY mode, an ALLOW rule is automatically created for the requesting client IP to prevent admin lockout.
Policy Change Protection
Changing between ALLOW and DENY clears existing rules to ensure consistent behavior.