HMAC Signature Header — Setup Guide

Add a signature header to Miterl probes so your WAF / CDN can identify and allow legitimate monitoring requests.

How it works

When HMAC signing is enabled on a monitor, Miterl probes attach a signature header to every outgoing HTTP request. The format follows the Stripe Webhook convention:

X-Miterl-Signature: t=1714112000,v1=a3b1...d9

The default header name is X-Miterl-Signature, but you can override it per monitor.

  • t is the Unix timestamp (lets you guard against replays)
  • v1 is HMAC-SHA256(secret, "<t>.<METHOD>.<PATH>") as a hex string
  • Query strings are not included in the signed payload

Setup steps

  1. On the monitor edit page, enable "HMAC signature header" and click "Generate" to mint a secret (or paste your own).
  2. Store the secret somewhere safe — it will not be shown again after saving.
  3. Use one of the WAF / CDN snippets below to allow signed requests through.

Cloudflare WAF

WAF Custom Rules are available on the Pro plan and above. On the Free plan, Bot Fight Mode cannot be fully bypassed via custom rules.

# Cloudflare WAF Custom Rule (Pro plan or above)
# Field: HTTP Header  → "X-Miterl-Signature"
# Operator: matches regex
# Value: ^t=\d+,v1=[a-f0-9]{64}$
# Action: Skip → All remaining custom rules + Bot Fight Mode

AWS WAF

Add this Allow rule to your WebACL at priority 0 to whitelist signed requests before any managed rules run.

# AWS WAF Rule (JSON snippet)
{
  "Name": "AllowMiterlProbes",
  "Priority": 0,
  "Action": { "Allow": {} },
  "Statement": {
    "ByteMatchStatement": {
      "FieldToMatch": { "SingleHeader": { "Name": "x-miterl-signature" } },
      "PositionalConstraint": "STARTS_WITH",
      "SearchString": "t=",
      "TextTransformations": [{ "Priority": 0, "Type": "NONE" }]
    }
  }
}

Nginx

# nginx (skip rate limiting / ModSecurity for signed requests)
map $http_x_miterl_signature $is_miterl_probe {
    ~^t=\d+,v1=[a-f0-9]{64}$  1;
    default                    0;
}

server {
    location / {
        if ($is_miterl_probe) {
            # bypass rules — set whatever flag your stack reads
            set $skip_modsec 1;
        }
        # ...
    }
}

Verify the signature on your origin (optional)

Checking that the header exists is usually sufficient, but you can verify the HMAC on your origin for stronger assurance. PHP example:

<?php
// On your origin: verify the signature is genuinely from Miterl.
// Use this if you want stronger assurance than "header exists".

\$header = \$_SERVER['HTTP_X_MITERL_SIGNATURE'] ?? '';
if (! preg_match('/^t=(\d+),v1=([a-f0-9]{64})\$/', \$header, \$m)) {
    http_response_code(401); exit;
}

[\$_, \$ts, \$sig] = \$m;
if (abs(time() - (int) \$ts) > 300) {
    http_response_code(401); exit; // replay protection: 5min window
}

\$secret = getenv('MITERL_HMAC_SECRET');
\$expected = hash_hmac('sha256', "{\$ts}.{\$_SERVER['REQUEST_METHOD']}.{\$_SERVER['REQUEST_URI']}", \$secret);

if (! hash_equals(\$expected, \$sig)) {
    http_response_code(401); exit;
}

FAQ

How do I rotate the secret?

Click "Generate" again on the monitor edit page and save. The next probe will sign with the new secret.

What if the secret leaks?

Rotate it the same way. The leaked secret immediately becomes invalid. If your WAF rule only checks for the header's presence, no rule changes are needed.

Can I include the query string in the signature?

Not currently. The signed payload is <METHOD>.<PATH> only — this avoids cache-key drift on CDNs that vary on query strings.