Rails Common Vulnerability Engine

If you ever need a local copy of the CVE list in your Rails application, you could consider using this engine.

RailsCVE gives you a RailsCVE::Entry model, on which you can perform various tasks, notably searching the CVE descriptions:

# in `rails console`

list = RailsCVE::Entry.search_plain 'ruby gem'
#=> SELECT "rails_cve_entries".*
#  FROM "rails_cve_entries"
#  WHERE (to_tsvector('english', description) @@ plainto_tsquery('ruby gem'))
#  ORDER BY "rails_cve_entries"."id" ASC

list.count
#=> 41

list.first
#=> #<RailsCVE::Entry
#   id: 48583,
#   name: "CVE-2011-0739",
#   description: "The deliver function in the sendmail delivery agent...",
#   references: [
#     "MISC:https://github.com/mikel/mail/raw/master/patches/20110126_sendmail.patch",
#     "CONFIRM:http://groups.google.com/group/mail-ruby/browse_thread/thread/e93bbd05706478dd?pli=1",
#     "BID:46021",
#     "URL:http://www.securityfocus.com/bid/46021",
#     "OSVDB:70667",
#     "URL:http://osvdb.org/70667",
#     "SECUNIA:43077",
#     "URL:http://secunia.com/advisories/43077",
#     "VUPEN:ADV-2011-0233",
#     "URL:http://www.vupen.com/english/advisories/2011/0233",
#     "XF:ruby-mail-deliver-command-execution(65010)",
#     "URL:http://xforce.iss.net/xforce/xfdb/65010"
# ]>

list.first.reference_uris
#=> [
#   "https://github.com/mikel/mail/raw/master/patches/20110126_sendmail.patch",
#   "http://groups.google.com/group/mail-ruby/browse_thread/thread/e93bbd05706478dd?pli=1",
#   "http://www.securityfocus.com/bid/46021",
#   "http://osvdb.org/70667",
#   "http://secunia.com/advisories/43077",
#   "http://www.vupen.com/english/advisories/2011/0233",
#   "http://xforce.iss.net/xforce/xfdb/65010"
# ]

Full text search capabilities

There exist two distinct search queries, which both are using Postgres' advanced text search capabilities:

  • RailsCVE::Entry.search_plain(str) and
  • RailsCVE::Entry.search_ranked(str)

While #search_plain does not predefine an order on the result set (except from ActiveRecord's default order), #search_ranked calculates a matching rank and uses this as sort criteria.

Keep in mind that creating a ranked search result requires a little more processing time and restricts the ActiveRecord query chaining possibilities:

# possible, does not reorder the query:
RailsCVE::Entry.search_ranked('ruby rails').first

# not possible, tries but fails to reorder by ascending rank:
RailsCVE::Entry.search_ranked('ruby rails').last

# not possible:
RailsCVE::Entry.search_ranked('ruby rails').search_ranked('windows')

# use this instead:
RailsCVE::Entry.search_ranked('ruby rails & windows')

Both search_ranked and search_plain accept an array of search fragments, which will result in a disjoint query:

RailsCVE::Entry.search_plain('ruby', 'rails').to_sql
#=> SELECT "rails_cve_entries".*
#   FROM "rails_cve_entries"
#   WHERE to_tsvector('simple', description) @@ (to_tsquery('simple', 'ruby | rails'))

Installation

This engine requires a PostgreSQL database!

Add rails_cve to your Gemfile and run bundle install:

gem 'rails_cve'

Then install and run the migrations via

rake rails_cve:install:migrations
rake db:migrate

and seed/import all currently knwon CVE entries (~70.000 at the time of writing):

rake rails_cve:seed

Repeat the last step if you'd like to rebuild the entire CVE database.

Schema format

As you can see in the example above, we take advantage of PostgreSQL's text search features. Hence, you will need to migrate to PostgreSQL unless you haven't already.

I should mention, that it is strongly recommended to change your schema format from Ruby to SQL, like so:

# in config/application.rb
config.active_record.schema_format = :sql

Maintenance

You should (at least daily) import the updates. RailsCVE currently uses the Cassandra web service. To do so, you need to call

RailsCVE::Entry.update_entries

This does not only import new entries, but also updates existing entries. These updates usually include updates in the references list and/or description text, but can also mark a CVE entry as candidate (CAN) or reject the entry. Currently, the updating method does not provide any hooks, but patches are welcome!

Tests

I'm working on it. Don't use this release unless you know what you're doing!

Contributing

Either

  1. open an issue and ask for directions

or

  1. Fork this repository.
  2. Commit your changes (tests are very welcome).
  3. Open a pull request.

License

MIT. See LICENSE file.