Veritas Payloads: a payload dataset that keeps itself current.
An open dataset of web application attack payloads, mapped to the OWASP Top 10 (2025), in one consistent schema. It refreshes itself every day from public security wordlists and is published as a static JSON API that the VERITAS scanner pulls from automatically.
01The problem
A scanner is only as good as the inputs it sends. VERITAS needed thousands of attack payloads for every OWASP Top 10 category, and for each one it needed to know where to inject it (a query string, a form field, a header, a JSON body) and how to tell whether it worked.
The material exists, but it's scattered across dozens of public wordlists and tools, each in its own format, with no injection point and no success check. And any copy taken once starts going stale the day it's taken, because those projects keep publishing new payloads.
02The approach
- One schema for everything. Every entry has an ID, OWASP category, target technology, injection point, the payload itself, and validation rules: the expected status code and a pattern that signals success.
- Organised the way a scanner reads it. Payloads are grouped by category and injection point, so the engine loads exactly the set it needs for the input it's testing.
- Published as an API, not a download. Static JSON pages that any system can fetch over HTTP, with no server to run or secure.
- Refreshed automatically. A scheduled job pulls the upstream sources every day, so new payloads reach scans without anyone touching the dataset.
{
"payload_id": "OWP-0055",
"vulnerability_category": "Injection (SQLi)",
"target_technology": "MySQL",
"injection_point": "query_parameter",
"payload_string": "' UNION SELECT 1,2,3--",
"validation": { "expected_status_code": 200, "success_regex": "2.*3" }
}
03How it grew
| When | Milestone |
|---|---|
| 21 Jun 2026 | First release: 51,752 payloads in 36 categories |
| 23 Jun 2026 | Added Exploit Database proof-of-concept payloads, an interactive dashboard on GitHub Pages, and full OWASP Top 10 (2025) coverage, with every category at 1,000+ payloads (123,918 total) |
| 6 Nov 2026 | Expanded to 345,994 payloads in 65 categories and published the static HTTP API |
| 7 Nov 2026 | Daily automatic sync from upstream sources goes live, with a public sync log; VERITAS starts pulling the dataset every day |
| 10 Nov 2026 | 346,133 payloads after the latest sync; the dataset grows whenever the sources publish something new |
04How the daily sync works
- 10 public sources
- GitHub Action
- payloads/
- JSON API
- VERITAS
- At 02:00 Malaysia time, a GitHub Action makes shallow checkouts of the ten source projects. If one source is down, it's skipped and the rest still sync.
- An importer reads them, keeps only web-application payloads, drops anything already in the dataset, and files each new entry under its category and injection point.
- If anything changed, the static API is rebuilt and the run is recorded in a public sync log: when it ran, how many payloads it added, and from which source.
- At 15:00 Malaysia time, a VERITAS background worker checks the latest commit. If it changed, it rebuilds its local corpus and writes each file atomically, so a scan that's running at that moment never reads a half-written file.
The API
| Endpoint | Returns |
|---|---|
index.json | Dataset totals and the endpoint map |
categories.json | All 65 categories with counts |
categories/{slug}/page/{n}.json | Up to 1,000 payloads, with next and prev links |
id-map/{bucket}.json | Any payload ID to its category and page |
sync-log.json | Every daily sync and what it added |
05Challenges & decisions
Serve an API with no server
GitHub can host files but can't run queries, so every endpoint is a pre-built file: paged categories plus an ID map that turns any payload ID into a single fetch. Nothing to run, patch or secure, and it's free to host.
Grow automatically without filling up with noise
The importer only accepts web-application payloads and skips anything already in the dataset. After one sync let some non-web strings through, I removed them and added a rule that rejects them on every future pull.
A sync that said it succeeded but delivered nothing
VERITAS's daily pull kept reporting success but adding zero payloads. I traced it to the dataset's change check: git rejected one of its arguments, the error read as "nothing changed", and the API rebuild was silently skipped while new payloads piled up behind it. I fixed the check, made a git error fail the run loudly instead, and added a drift check that rebuilds the API whenever it no longer matches the dataset, so a missed rebuild repairs itself on the next run.
GitHub's 100 MB file limit
The per-category files and the API are the source of truth. The single all-in-one download is regenerated only while it fits under the limit, so growth never blocks a sync.
A scheduled job that reports success isn't proof that the data arrived. The fix was to check the published result, not just the exit code.
06Outcome
Veritas Payloads is live at payloads.saifuliqbal.dev, with an interactive dashboard, an API guide and the public sync log. The source is on GitHub.
It grew from 51,752 payloads to over 346,000, and it now updates itself: new payloads published by the security community reach every VERITAS scan within a day, with no manual step.
Use it only for testing systems you're authorised to assess. Get in touch if you'd like to use it or contribute.