Dhal combines deterministic request controls with route-specific policy. Start with broad monitoring, then enforce only where the application behaviour is understood.
Rule families
Dhal v1 includes controls for:
- IP allow and block lists;
- SQL injection, cross-site scripting, path traversal, SSRF, RCE, SSTI, GraphQL abuse, and common probe signatures;
- request-size limits;
- header anomalies and conflicting forwarding headers;
- content-type consistency;
- JSON API positive-security constraints;
- bot and automation signals;
- honeypot headers, query parameters, and paths;
- credential-stuffing failure thresholds;
- request rate limits and IP reputation.
Rule packs
Available rule packs are:
generic-webapiauthwordpressstrict-api
{
"rules": {
"packs": ["generic-web", "api"],
"sqli": true,
"xss": true,
"pathTraversal": true,
"badUserAgents": true
}
}Use the CLI to review the rule inventory before enforcement:
npx dhal rulesRoute profiles
Route profiles can override the global mode, rules, limits, reputation behaviour, and blocking response.
{
"schemaVersion": "1",
"mode": "monitor",
"routes": {
"/api/login": {
"mode": "block",
"tags": ["authentication"],
"rateLimit": {
"enabled": true,
"windowSeconds": 60,
"max": 20,
"keyBy": ["ip", "route"]
},
"rules": {
"credentialStuffing": {
"enabled": true,
"windowSeconds": 300,
"maxFailures": 4,
"keyBy": ["ip", "route", "userAgent"]
}
},
"response": {
"blockStatusCode": 429,
"message": "Too many authentication attempts"
}
}
}
}Patterns support exact paths and * wildcards:
{
"routes": {
"/api/admin/*": { "mode": "strict" },
"/api/public/*": { "mode": "monitor" }
}
}When multiple patterns match, Dhal selects the most specific pattern by comparing the non-wildcard length.
Set enabled: false on a profile to ignore that profile and use the global configuration.
Bot false-positive controls
Bot detection uses multiple signals rather than relying on a single user-agent string.
{
"rules": {
"bot": {
"enabled": true,
"scoreThreshold": 70,
"blockEmptyUserAgent": false,
"allowUserAgents": ["trusted-monitor/1.0"],
"falsePositiveControls": {
"minSignals": 2,
"skipStaticAssets": true,
"ignorePaths": ["/health", "/ready"],
"ignorePrivateIps": false
}
}
}
}Prefer raising minSignals, adding a narrow allow entry, or applying a route-specific override before disabling bot controls globally.
JSON API positive security
{
"rules": {
"api": {
"enabled": true,
"requireJsonContentType": true,
"allowedContentTypes": ["application/json", "application/problem+json"],
"methodsWithBody": ["POST", "PUT", "PATCH"],
"maxJsonDepth": 20,
"maxJsonKeys": 500
}
}
}Apply this globally only to JSON-only services. For mixed applications, enable it on API route profiles.
Suppressions
Suppressions are explicit policy exceptions and remain visible in audit metadata.
{
"policy": {
"suppressions": [
{
"id": "approved-validation-scanner",
"enabled": true,
"ruleId": "honeypot.triggered",
"path": "/.well-known/security-canary",
"reason": "approved internal validation scanner",
"expiresAt": "2027-01-01T00:00:00.000Z"
}
]
}
}Suppressions can match a rule, category, route, path, IP, user, tenant, or API-key identity. Keep them narrow, document the reason, and set an expiry date.
Severity and sampling
Use policy.severity to map categories or individual rule IDs to info, low, medium, high, or critical. Sampling can reduce allowed-event volume while always retaining blocked and would-block events.
Do not use sampling as a substitute for alert tuning or storage controls.