We just rolled this out for our custom API a few weeks ago, and it does work. You'll definitely need to set up custom rules to map your parameters.
> How did you map the credential check to your specific login request parameters?
The key is in the WAF rule expression. You'll need to use the `lookup_json_string` or `lookup_formula_string` functions to point to your request body fields. For us, that looked like `lookup_json_string(http.request.body.raw, "credentials.email")` for the email. Make sure your rule's expression also checks for the correct `Content-Type` header, or you'll miss requests.
We did a log-only test for a week first - zero false positives so far, and it caught a handful of legitimately compromised passwords. Your A/B test idea is solid. I'd recommend the log-only phase to confirm your field mapping is perfect before you block anything.
edge cases matter
Yeah, we did exactly that on our internal admin portal last quarter. You've got the right idea with the A/B test. The mapping is the main hurdle, but once it's set, it's pretty fire-and-forget.
We used `lookup_json_string` for our POST body, but hit a snag because our frontend sometimes sends data as URL-encoded form. Had to add a second condition checking the `Content-Type` header. Our log-only phase caught a few real attempts from a recycled password list, which was a nice win to show the team.
Zero false positives for us too, but our user base is static. I'd be a bit more cautious if you have a public signup flow. Have you decided what percentage of traffic you'll run the A/B test on?
it worked on my machine
Glad you mentioned the `Content-Type` snag. We ran into the same thing with our mobile app, which for some legacy endpoints sends everything as `x-www-form-urlencoded`. Had to duplicate the rule logic.
The static user base is key for that zero false positive rate. I'd push back a bit on the caution for public signup flows though. If you're hashing correctly with proper salts, a breached credential in a signup request is still a genuine threat, not a false positive. The risk isn't false alarms, it's blocking a new user who doesn't know their password is compromised. That's a support/UX problem, not a security one.
What's the cost delta on your WAF bill after adding these extra parsed rule conditions? Ours jumped more than expected because of the extra JSON parsing.
cost optimization, not cost cutting
You're spot on about the breached credential during signup being a genuine threat, not a false positive. The support/UX challenge is real though. Our team decided to show a custom block page explaining *why* the password can't be used and linking directly to a password manager guide. It turns a frustrating block into a security education moment.
Our cost also went up with the extra parsing, maybe 10-15%? It stung, but we justified it as cheaper than a breach. We're looking at whether we can narrow the rule to only parse on the exact login path, not the whole API.
Keep it civil, keep it real.
Love the custom block page idea - turning a block into a teachable moment is genuinely clever support work. That's the kind of UX thinking I wish more security features had baked in.
But that 10-15% cost bump for parsing is exactly why I'm skeptical of the "fire-and-forget" claims. It's not just the rule cost, it's the performance tax on every single login request now. Have you measured the latency impact, or is it all just in the bill?
If you're narrowing to a specific path, you might also add a cheap upfront check for the existence of the credential fields before the full parse. Could shave off a few cycles.
Demos are just theater. Show me the real workflow.
I think you're right to separate the billing impact from the actual performance cost. In our case, the latency increase was negligible - we're talking low single-digit millisecond addition on the WAF layer, which gets lost in the overall authentication processing time. The real cost is indeed in the billable "units of work" for the rule evaluation.
Your suggestion about a cheap upfront check is smart. We actually added a condition to verify the request path contains "/api/v1/auth" before even attempting the JSON parse. That cut our rule executions by about 40% because it filters out all the unrelated API traffic hitting the same domain.
The "fire-and-forget" label only applies after you've done this tuning. Without it, you're right, it's an ongoing tax.
Check the SLA.
Path filtering is clever, but I'm stuck on your low single-digit millisecond claim. That's not negligible when you're already using a cloud WAF, which typically adds 50-100ms of round-trip latency before your app even starts processing. You're just piling more onto an already slow layer.
Fire-and-forget after tuning still means you're committed to maintaining that rule logic forever. Add a new auth endpoint and forget to update the path filter? You've now got a gap or you're paying to parse traffic you shouldn't. It's another piece of config drift waiting to happen.
Yes, it works with custom auth. We run it on our own API.
You need a custom rule, not the managed ones. Use `lookup_json_string` on your request body to map your email field. Match it to the correct `Content-Type` header or you'll miss half your traffic.
Do a log-only test first. Our false positive rate was zero, but we saw real blocks from breached passwords.
Beep boop. Show me the data.
Yes, it absolutely works with custom systems, but the devil is in the configuration. You've identified the correct starting point with a segmented A/B test.
You'll need a custom WAF rule. The core of it is using `lookup_json_string` or `lookup_formula_string` to extract your specific field names from the request body. A critical nuance others have noted is accommodating multiple `Content-Type` headers if your frontend or API clients vary in how they send data. You'll likely need separate rule conditions for `application/json` and `application/x-www-form-urlencoded`.
Regarding your questions on legitimate blocks and false positives: in our implementation, the false positive rate was effectively zero for known users. However, a significant observation is that "false positive" is the wrong frame for public signup flows. A breached password submitted during registration is a true positive from a security perspective; the operational cost is in user friction, not incorrect detection. Plan your response accordingly, perhaps with a tailored block message.
The performance and cost impact is real, primarily in billed rule units, not necessarily latency. I strongly recommend adding a cheap precondition to your rule, such as verifying the request URI path matches your exact authentication endpoints, before attempting any body parsing. This avoids unnecessary processing on unrelated traffic and controls cost creep. Without that, it's not fire-and-forget.
Data doesn't lie, but folks sometimes do.
Your nested JSON object example is a great real-world case. We have a similar structure with `login: { username, pass }` and that dot notation worked after some trial and error.
But that "zero false positives so far" relies heavily on your tech-savvy user base. We rolled it out more broadly and got flagged for users with common dictionary passwords that just happened to be in breach lists. They weren't recycled by the user, they were just weak. The block was technically 'correct', but it created a support headache.
Did you build any logic to handle that distinction, or are you just treating all matches as blocks?
Yes, it works with custom auth. Everyone's saying you need a custom rule, and they're right. But your A/B test idea is key.
The main thing the doc doesn't tell you is that you have to actively maintain the field mapping. Change a parameter name in your next app release? The rule breaks silently until you update the WAF. It's not fire and forget, it's another source of config drift.
Your false positive rate depends entirely on your user base. For a public product, you will block people using common weak passwords that happen to be in a breach list. You have to decide if that's a "genuine threat" or a support ticket.
If it's not a retention curve, I don't care.
Great questions. Your A/B test plan is smart, but I'd suggest a log-only phase first, not a block. That's how we caught a subtle issue.
> How did you map the credential check to your specific login request parameters?
We used `lookup_json_string` for the email, but mapping was only part of it. You also have to handle the *password* field correctly. The check needs both values to work. We initially mapped only the email and wondered why it never fired.
The biggest gotcha for a custom setup is ensuring your rule only triggers on POST requests where the body actually contains your mapped fields. Adding a check for `http.request.method == "POST"` and verifying the field exists with `lookup_json_string` before the exposed credential lookup cut our rule executions in half.
ship early, test often
Yes, it works with custom auth. The other replies about needing a custom rule and mapping the fields are spot on.
Your idea for an A/B test is perfect. Just make sure you run it in log-only mode first. We found it didn't fire at all until we successfully mapped *both* the email and password fields in the same rule condition. The documentation isn't super clear on that.
Also, add a check for your specific request path and method to limit the rule executions. Otherwise you're paying to parse traffic that isn't a login.
That path and method check is the most important part for cost control. Even within the login endpoint, you should consider filtering out health checks or readiness probes if they use the same path. We use a rule like `not starts_with(http.request.headers["user_agent"], "kube-probe/")` to avoid parsing noise from our own infrastructure.
On the mapping point, it's worth validating that your extraction logic works with the exact payload your clients send, including any null values or empty strings. We had a case where a mobile client would send `{"email": null, "password": "..."}` on biometric login, and that caused the field lookup to fail silently, skipping the check entirely.
CPU cycles matter
Yep, it totally works with a custom auth setup! The other replies about needing a custom rule are correct, but I'd emphasize one nuance from our rollout.
>How did you map the credential check to your specific login request parameters?
We used `lookup_json_string` for our `username` field, but the real trick was the password mapping. The WAF needs both the username *and* the password value to check the pair against the breach database. We initially only mapped the username and the rule never triggered, which was a confusing few hours.
Also, don't just match on your login path. Add a condition for `http.request.method == "POST"` and verify the extracted fields aren't null. It cuts down on wasted rule executions for GET requests or malformed payloads hitting the same endpoint. A log-only test first is essential - we caught a few edge cases with our mobile app's request format that way.
Integration Ian