加载中…
加载中…
A small neural network (1,959,361 parameters) that scores how likely a
string is a cross-site scripting (XSS) payload. It reads raw characters after
undoing URL and HTML encoding, so %3Cscript%3E, <script> and <ScRiPt>
look the same to it. It was trained from random weights; no pretrained model or
tokenizer is involved.
Use it to triage inputs: request parameters, form fields, log lines, user-supplied HTML. A high score means "looks like an injection payload". It does not prove that a payload would execute, and a low score does not prove an input is safe. Keep context-aware output encoding and a Content Security Policy in place regardless.
pip install torch numpy safetensors huggingface_hub
from huggingface_hub import hf_hub_download
import importlib.util
path = hf_hub_download("hareramray325/websec", "xss_detector.py")
spec = importlib.util.spec_from_file_location("xss_detector", path)
xss_detector = importlib.util.module_from_spec(spec)
spec.loader.exec_module(xss_detector)
detector = xss_detector.XSSDetector.from_pretrained("hareramray325/websec")
detector.predict(["<img src=x onerror=alert(1)>", "<b>hello</b>"])
# [{'text': '<img src=x onerror=alert(1)>', 'score': ..., 'is_xss': True},
# {'text': '<b>hello</b>', 'score': ..., 'is_xss': False}]
xss_detector.py is plain Python in this repository; read it before running it.
The weights are in model.safetensors, so loading them executes no code.
detector.score(texts) returns calibrated probabilities; predict applies the
threshold 0.7278, tuned on validation data for 0.1% false alarms.
Pick your own threshold if your traffic differs.
Trained for 12 epochs (epoch 9 kept) on an NVIDIA RTX 5050 laptop GPU in about 4 minutes, with AdamW, a cosine learning-rate schedule and an averaged copy of the weights.
| Source | Used for | License |
|---|---|---|
| Mereani & Howe XSS dataset | XSS attack URLs and payloads; benign URLs, JavaScript and text | MIT |
| Generated benign samples | Everyday HTML, URLs, code and prose that a naive model mistakes for attacks | Created for this model |
| Benign copies of attack URLs | Same sites and parameter names with the payload replaced | Derived from Mereani |
After normalising, exact duplicates and texts with conflicting labels were removed,
leaving 68,258 rows, split 70/15/15 into training, validation and test.
During training, each epoch adds varied copies of training attacks (real actions
such as cookie theft or redirects in place of alert(1), other event handlers,
payloads placed inside ordinary text, URLs or JSON), template-built attacks, and
benign look-alikes (prose and code that mention onclick, <script> or cookies).
Site names in URLs are swapped in both classes so that no domain predicts a label.
Validation and test rows are never varied.
The public web-attacks-long dataset was deliberately left out because it states no license. Every training row comes from an MIT-licensed source or was generated for this model.
Both columns use the same data and splits. The linear baseline is character TF-IDF with logistic regression, trained on the same training rows, at its own validation-tuned threshold.
| Measurement | This model | Linear baseline |
|---|---|---|
| Held-out attacks caught | 2,131 / 2,155 (98.9%) | 2,126 (98.7%) |
| Held-out false alarms | 6 / 8,084 (0.07%) | 11 (0.14%) |
| Held-out detection at exactly 0.1% false alarms | 98.9% | 98.0% |
| External attacks caught (SecLists) | 7,712 / 7,896 (97.7%) | 7,604 (96.3%) |
| External attacks matching no training-pool row | 7,282 / 7,460 (97.6%) | 7,176 (96.2%) |
| External benign false alarms (WikiText, OpenAssistant) | 5 / 6,993 | 0 |
| Hand-written challenge attacks caught | 60 / 60 | 58 |
| Hand-written challenge false alarms | 0 / 80 | 0 |
External benchmark: 7,896 payloads from nine SecLists lists (MIT) and 6,993 paragraphs and messages from WikiText and OpenAssistant. Nothing was trained or tuned on it. Many SecLists payloads also occur in the training sources, so the row counting only lines that match no row of the training pool is the stricter one.
Challenge set: 140 hand-written strings. Its past mistakes guided the training-time variation, so treat it as a regression check, not an independent test. Missed: none
<iframe src=...>, <script src=...> and
<form> in an input are scored high, as the training data labels them. Do not
run it over whole web pages.Defensive: triaging inputs and logs, flagging suspicious values for review, and measuring how well a filter copes with encoded payloads. It is not a web application firewall on its own, and it was not built or evaluated for generating payloads.