Adversarial input for Ruby — like Faker, but evil.
Faker gives you data that looks real. EvilFaker gives you data that fights back: the strings that have historically broken software.
EvilFaker::Injection.sql.sample #=> "' OR 1=1 -- 1"
EvilFaker::Zalgo.sample #=> "Ṱ̺̺̕o͞ ̷i̲̬͇̪͙n̝̗͕v̟̜̘̦͟o̶̙̰̠kè͚̮̺̪̹̱̤"
EvilFaker::Unicode.quotes.sample #=> "<foo val=“bar” />"
EvilFaker::Emoji.sample #=> "👨🦰"Emoji that get truncated by a utf8 MySQL column. Right-to-left overrides that
flip your layout. Zalgo that overflows its line. Reserved Windows filenames.
SQL, XSS, XXE, LDAP, SSTI, and 20 other kinds of injection payload.
# Gemfile
group :development, :test do
gem "evil_faker"
endEvery namespace answers to the same three methods:
EvilFaker::Reserved.all # every string in the group (Array)
EvilFaker::Reserved.sample # one at random
EvilFaker::Reserved.sample(3) # three at randomNamespaces that bundle several kinds of input expose subtypes, same API:
EvilFaker::Injection.sql # only the SQL payloads
EvilFaker::Injection.script # only the XSS payloads
EvilFaker::Injection.sql.sampleThe full list of namespaces, subtypes, and real sample output lives in GENERATORS.md so this README stays readable.
EvilFaker doesn't generate strings on the fly — it vendors them from four public wordlists that have been breaking real software for years:
| Source | Contributes |
|---|---|
| Big List of Naughty Strings — Max Woolf | Emoji, RTL overrides, zalgo, unicode edge cases, base injection payloads |
| PayloadsAllTheThings — Swissky & contributors | Deep SQL/XSS/XXE/SSTI/LDAP/NoSQL payloads, admin routes, cache-deception headers |
| IntruderPayloads — 1N3 & contributors | More SQL/XSS/traversal/command payloads, malicious upload filenames |
| fuzzdb — fuzzdb-project | XPath, RFI, SSRF, JSON, format strings, magic hashes, valid/invalid emails |
When more than one source has data for the same group, .all and every
subtype method return all of it, concatenated — nothing gets dropped in
favor of another source. EvilFaker::Injection.sql, for example, merges four
separate files into 2,776 lines (8 from BLNS, 661 from fuzzdb, 753 from
IntruderPayloads, 1,354 from PayloadsAllTheThings).
The one thing that doesn't happen automatically is cross-source dedup: each
source de-dupes its own file at vendor time, but two sources that happen to
share the same payload aren't checked against each other (fuzzdb and
PayloadsAllTheThings overlap a lot, since the latter originally copied
several fuzzdb files). Call .uniq yourself if that matters for your case.
Per-file origin and license details live in NOTICE.md — worth a read before you ship this anywhere public, since two of the four sources (IntruderPayloads, fuzzdb) don't declare a license upstream.
RSpec.describe "GET /search", type: :request do
EvilFaker::Injection.sql.each do |payload|
it "survives #{payload.inspect}" do
get "/search", params: { q: payload }
expect(response).to have_http_status(:ok) # no 500
expect(User.count).to eq(3) # table still there
end
end
endSample large groups so the suite stays fast:
EvilFaker::Injection.script.sample(10).each do |xss|
it "escapes #{xss.inspect}" do
# ...
end
endfactory :evil_faker_user, parent: :user do
name { EvilFaker::Unicode.sample }
bio { EvilFaker::Zalgo.sample }
endsample is random and unseeded — don't rely on it in a spec that needs to be
reproducible. Use the Array you already have instead:
EvilFaker::Injection.sql.first
EvilFaker::Injection.sql.find { |s| s.include?("DROP") }bin/setup # install dependencies
bundle exec rspec # run the tests
bundle exec rubocop # lint
bin/console # IRB with evil_faker loaded
ruby scripts/blns_build_corpus.rb # regenerate groups/blns from blns.txt
ruby scripts/payloads_all_the_things_build_corpus.rb # regenerate groups/payloads_all_the_things (needs gh CLI)
ruby scripts/intruder_payloads_build_corpus.rb # regenerate groups/intruder_payloads (needs gh CLI)
ruby scripts/fuzzdb_build_corpus.rb # regenerate groups/fuzzdb (needs gh CLI)
ruby scripts/generate_namespaces.rb # regenerate lib/evil_faker/groups from data/groupsBase discovers sources off the filesystem, not off a hardcoded list —
adding a fifth source is just adding a groups/<source>/ folder with files
in the right shape and re-running generate_namespaces.rb.
MIT-licensed corpus data from the four sources above, credits and full license text in NOTICE.md.
MIT. See LICENSE.txt.