EvilFaker 💎

Adversarial input for Ruby — like Faker, but evil.

Gem Version Ruby License: MIT

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.

Installation

# Gemfile
group :development, :test do
  gem "evil_faker"
end

Quickstart

Every 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 random

Namespaces 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.sample

The full list of namespaces, subtypes, and real sample output lives in GENERATORS.md so this README stays readable.

Where the data comes from

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.

Usage patterns

In your specs

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
end

Sample large groups so the suite stays fast:

EvilFaker::Injection.script.sample(10).each do |xss|
  it "escapes #{xss.inspect}" do
    # ...
  end
end

In a factory

factory :evil_faker_user, parent: :user do
  name { EvilFaker::Unicode.sample }
  bio  { EvilFaker::Zalgo.sample }
end

Forcing an exact value

sample 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") }

Development

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/groups

Base 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.

Credits

MIT-licensed corpus data from the four sources above, credits and full license text in NOTICE.md.

License

MIT. See LICENSE.txt.