August 22, 2026
Beyond Static Wordlists: Using Logistic Regression and Naive Bayes to Prioritize Payloads in Bug…
How to turn web application context into an intelligent test ranking — without letting AI make the final vulnerability decision

By Arthur Johann Wilmsen Witt
8 min read
When a scanner discovers a parameter, it must make a decision: which tests should it run first?
The most common solution is to use a static wordlist. The scanner walks through a list of payloads and sends each item, usually in the same order, regardless of context. This strategy is simple and can uncover vulnerabilities, but it can also generate a large number of unnecessary requests.
A parameter named redirect_uri, for example, should not necessarily receive the same initial test sequence as a numeric field named product_id. Input reflected inside an HTML attribute has a different context from a value inserted into a JSON structure. Likewise, the detected technology, HTTP method, content type, and previous responses can all change which tests are most relevant.
This problem led me to think about a machine-learning-based payload selection engine: instead of testing everything in the same order, use context to prioritize the payload families most likely to produce a useful signal.
The goal is not to let an AI model declare that it has found a vulnerability. The model has a narrower — and more realistic -job: reduce the search space and organize the testing queue.
This article focuses exclusively on testing conducted in labs, on systems you own, or within programs that provide explicit authorization. The prototype only ranks test categories; it does not send requests or contain working exploit payloads.
The Problem with Static Wordlists
According to the OWASP Web Security Testing Guide, fuzzing involves sending inputs to a target and analyzing response characteristics such as status codes, timing, and behavior. Automation reduces manual work, but it gives the scanner another challenge: deciding what to test and interpreting what happened.
Consider a simplified catalog with five test families:
- HTML reflection testing;
- query-like input testing;
- URL-handling testing;
- redirect testing;
- template expression testing.
If each family contains dozens of variations and the application exposes thousands of parameters, the number of combinations grows quickly. The scanner consumes more time, creates noise, triggers rate limiting, and increases the chance of being blocked by a WAF.
The problem is not necessarily the wordlist itself. A wordlist is still useful as a catalog of known tests. The problem is running the entire catalog without considering context.
Instead of replacing wordlists, machine learning can reorder them.
What Should the Model Actually Predict?
An initial approach would be to train a classifier with labels such as XSS, SQL injection, SSRF, SSTI, and open redirect. For each parameter, the model would choose one of those classes.
This formulation has an important limitation: the same input point may be relevant to more than one famil — or to none of them. Forcing the model to choose exactly one class creates an artificial answer.
A more flexible approach is to represent each example as a pair:
observed context + candidate test family
The target then becomes binary:
1: the family produced a confirmed, relevant signal;0: the family did not produce a confirmed signal.
During a scan, the scanner creates one copy of the current context for every available family, calculates the scores, and sorts the tests from highest to lowest.
The result is not "this parameter has SSRF." It is something closer to:
| Rank | Test family | Estimated score | | — -:| — -| — -:| | 1 | URL-handling input | 0.81 | | 2 | Redirect | 0.63 | | 3 | HTML reflection | 0.22 | | 4 | Query-like input | 0.09 | | 5 | Template expression | 0.04 |
The scanner still needs to execute the test and confirm the behavior through deterministic rules, response analysis, or manual review.
Which Features Could Be Used?
The model must receive signals that are available before the candidate family is executed. Otherwise, data leakage occurs: training relies on information that will not exist when the real decision must be made.
Possible features include:
| Group | Examples | | — -| — -| | Request | HTTP method, parameter location, content type, and route extension | | Parameter | name, apparent type, URL-like value, numeric value, or JSON structure | | Baseline response | status code, length, response time, content type, and harmless reflection | | Technology | server, framework, language, CDN, and detected WAF | | Reflection context | HTML, attribute, JavaScript, JSON, header, or no reflection | | Authorized history | previous results from the same application or technology | | Candidate | the test family currently being evaluated |
An initial harmless probe can check whether a value appears in the response and identify its context. That information can be used for ranking because it is known before the next tests are selected.
An error caused by a specific payload, however, cannot be used to decide whether that same payload should be sent. It can only become part of the history after the attempt.
Building the Dataset
The dataset should record attempts performed in authorized environments. One possible schema is:
application_id endpoint_id parameter_name parameter_location http_method content_type reflection_context detected_technology waf_detected baseline_status baseline_time_ms candidate_family confirmed_signal confirmation_method timestamp
The confirmed_signal field should not simply mean that the response changed. Differences in response length, status, or timing can happen for many reasons. A positive label should follow reproducible criteria, such as a reliable deterministic rule, controlled confirmation in a lab, or documented manual review.
Negative results must also be stored. If the dataset contains only successful attempts, the model will never learn how to distinguish relevant contexts from combinations that produce no useful signal.
The Risk of Learning the Target Instead of the Pattern
Randomly splitting individual rows into training and test sets can produce misleading results. Requests from the same domain, endpoint, or template may appear in both partitions. In that case, the model memorizes characteristics of a particular application and appears to generalize better than it actually does.
One solution is to split the data by application. For example, keeps groups separate across folds. For this project, each application_id can act as a group.
An even stricter evaluation could combine application-level separation with a temporal split: train on older data and test on applications or time periods the model has not seen.
Why Logistic Regression?
Despite its name, Logistic Regression is a classification algorithm. In a binary problem, it combines the features and transforms the result into a value between zero and one.
The weights w show how each feature influences the decision. This is useful in security because it makes the model easier to inspect.
If the combination parameter_location=query, is_url_like=true, and candidate_family=url_input increases the score, that relationship can be examined. If an irrelevant feature dominates the result, the problem is also easier to identify.
Logistic Regression is a strong candidate for this engine because it:
- works with numeric, binary, and encoded categorical features;
- provides ranking scores through
predict_proba; - is fast to train and run;
- supports regularization;
- exposes coefficients that help explain decisions;
- provides a strong first model before moving to more complex architectures.
The scikit-learn documentation describes its probability estimates for classification. For ranking, the relative order of the scores may matter more than interpreting 0.81 as a perfectly calibrated probability. If the system uses absolute thresholds to stop testing, probability calibration should be evaluated separately.
Where Does Naive Bayes Fit?
Naive Bayes is an excellent baseline. It is fast, simple, and particularly effective with sparse representations such as word or token counts.
The parameter name, route, and detected technology can be transformed into a small document:
param redirect_uri location query method GET content html family redirect
This text can be vectorized and classified with MultinomialNB or ComplementNB. According to the scikit-learn documentation, the multinomial model is suitable for discrete features such as the counts used in text classification. For purely boolean indicators, BernoulliNB is another option.
Its main limitation is the "naive" feature-independence assumption. In a scanner, many signals are correlated: framework, server, headers, cookies, WAF, and response format may all describe parts of the same technology stack. This can make Naive Bayes overly confident about certain combinations.
For that reason, I would use:
- Logistic Regression as the primary model, combining categorical and numeric features;
- Naive Bayes as a baseline, especially for tokens derived from parameter names, routes, and technologies.
If Logistic Regression does not clearly outperform the baseline, the dataset may still be too small, the labels may be noisy, or the features may not contain enough useful signal.
Accuracy Does Not Answer the Main Question
If only 2% of context-family combinations are positive, a model that always predicts "no" will achieve 98% accuracy while being completely useless for prioritization.
Precision, recall, and F1-score help evaluate the binary classifier, but the final product is a ranking system. I would therefore focus on the following metrics:
Hit@K
The percentage of contexts in which at least one useful family appears within the first K positions.
If Hit@3 = 0.85, then in 85% of contexts with at least one positive result, the first relevant family appeared among the top three candidates.
Mean Reciprocal Rank
The average inverse rank of the first useful result. Finding the right family in first place is worth more than finding it in fifth place.
Requests Until the First Signal
How many attempts are required, on average, before a relevant result appears?
This metric connects the model to the practical goal: reducing scan traffic and execution time.
Coverage
How many relevant families were never executed because of the ranking or confidence threshold?
Aggressively reducing requests can look efficient, but it becomes dangerous when it increases false negatives too much.
Comparison Against Baselines
The engine should be compared against at least four strategies:
- fixed wordlist order;
- random order;
- Naive Bayes;
- Logistic Regression.
Without this comparison, there is no way to know whether the model learned anything more useful than a simple heuristic.
The Model Should Prioritize, Not Eliminate
A safe way to introduce the system is to use ranking only to determine test order. Every authorized family is still executed, but the most promising ones run first.
After measuring coverage, the scanner can introduce request budgets:
- execute the top three families;
- continue if an intermediate signal appears;
- fall back to the full wordlist when confidence is low;
- never remove mandatory checks selected by the user;
- reduce request speed when a WAF or rate limiting is detected.
This creates a hybrid architecture. Machine learning organizes priorities, while deterministic rules retain security controls and confirm results.
Limitations
An engine like this would face several challenges:
- small and imbalanced datasets;
- differences between labs and real applications;
- changes in technologies and protection mechanisms;
- incorrect labels produced by heuristics;
- excessive repetition of a few frameworks or domains;
- correlated features;
- the risk of optimizing the scanner only for already known vulnerability patterns;
- loss of coverage when the model becomes overly confident.
There is also a feedback loop. If the scanner stops executing low-scoring families, it stops collecting examples for those families. Future datasets then begin to reflect the model's own previous decisions.
One solution is to reserve part of the request budget for controlled exploration. Some low-scoring candidates should still be tested so the system does not become trapped by its own predictions. In a future iteration, this problem could be studied as a contextual bandit, balancing exploration and exploitation.
Conclusion
Machine learning does not need to replace a traditional scanner to be useful in bug bounty.
A more realistic application is to let the model answer a limited question:
Given this context and this test family, how high should its priority be?
Logistic Regression is a strong starting point because it combines different feature types, produces ranking scores, and exposes coefficients that can be inspected. Naive Bayes provides a fast baseline, especially when parameter names, routes, and technologies are represented as tokens.
The value of the system should not be measured by accuracy alone, but by its ability to surface relevant signals earlier, reduce requests, and preserve coverage.
In the end, the model does not prove that a vulnerability exists. It only decides where to look first.
And that may be one of the most interesting applications of artificial intelligence in offensive security: not replacing the analysis process, but making the search more contextual, measurable, and efficient.