Fastly Next-Gen WAF
CDN and WAF
Also known as: Signal Sciences, SigSci, Fastly Bot Management
Best known for blocking on 406 Not Acceptable, a status code almost nothing else uses, which makes an unexplained 406 a strong vendor fingerprint.
Fastly's Next-Gen WAF is the former Signal Sciences product, and it inherited an unusual default: blocked requests are answered with 406 Not Acceptable rather than 403. Because 406 legitimately means the server cannot produce a representation matching the request's Accept header, and because almost no real application ever emits it, an unexplained 406 on an endpoint that normally returns JSON or HTML is one of the more distinctive signatures in this glossary.
The blocking status code is configurable per agent, so a given deployment may return 403 instead. The default is what makes 406 worth recognising.
Signal Sciences works by accumulating signals against a source over a decision window rather than judging a single request, so a client often gets several normal responses before blocking begins. That lag is characteristic and it misleads people into blaming whatever they changed last.
How to identify it
- 406 Not Acceptable on a request whose Accept header the server could obviously satisfy.
- A short, generic block body with no vendor branding, since Signal Sciences deployments are typically unbranded.
- Fastly CDN headers such as x-served-by, x-cache, and via alongside the refusal, when the WAF runs on the Fastly edge.
- Blocking that begins after a burst rather than on the first request, reflecting the decision window.
Headers
- x-served-by: Fastly cache node identifier. Indicates the Fastly edge, not the WAF decision itself.
Status codes
406 Agent block
Blocked. Operator configurable.
The Next-Gen WAF agent blocked the request. 406 is the historic Signal Sciences default and remains the most recognisable signature of the product.
What triggers it
- Enough attack or anomaly signals accumulated against the source within the decision window to cross the blocking threshold.
- A rule matching request content, such as an injection signal or a flagged path.
- Source reputation from Fastly's network learning exchange.
How to confirm it
- 406 with a terse body on an endpoint with no content negotiation.
- Fastly edge headers on the same response.
What to do about it
- Do not treat it as content negotiation. Changing the Accept header will not help, and this is the usual wasted first move.
- Because the decision is accumulated, look back over the preceding minutes rather than at the single failing request. Something earlier in the burst raised the signals.
- Reduce concurrency and re-check. Thresholds decay, so a source can recover once the window rolls off.
HTTP/2 406 content-type: text/html x-served-by: cache-lhr1234-LHR <html><head><title>406 Not Acceptable</title></head><body></body></html>
403 Configured block response
Blocked. Operator configurable.
The same block decision, on deployments where the operator changed the response status to the more conventional 403.
What triggers it
- The same signal accumulation as the 406 case.
How to confirm it
- Indistinguishable from a generic 403 without other Fastly markers, which is why operators choose it.
What to do about it
- Use the timing signature rather than the code: a source that works and then stops working part way through a burst fits an accumulating WAF better than a static rule.
429 Rate limiting rule
Rate limited. Observed behaviour.
A rate limiting rule fired against the source.
What triggers it
- Request rate above the configured threshold for the rule's window.
How to confirm it
- Sometimes retry-after, alongside Fastly edge headers.
What to do about it
- Back off, honour Retry-After where present, and lower concurrency.
If you run a site behind it
- 406 is genuinely useful as a private signal because it is rare, but it confuses integrators and some HTTP clients handle it badly. Decide whether that is a feature or a support burden for your API consumers.
- The decision window means legitimate bursty clients can trip thresholds well after their burst started. Check flagged sources against your own known integrations before tightening.
If your traffic is being caught by it
- An unexplained 406 is one of the most identifiable anti-bot responses there is. Learn it and you will save an afternoon.
- The failure is about accumulated behaviour, so the fix is pacing and concurrency rather than headers.