From 81d252b6a2e2960d68b2b8f1e8a99d8f7902565d Mon Sep 17 00:00:00 2001 From: Dennis Paagman Date: Sun, 17 May 2026 19:51:31 +0200 Subject: [PATCH 1/2] Add json schema and validate yml files --- Gemfile | 7 +- spec/schema_validation_spec.rb | 66 +++++++++++++++ spec/schemas/gem.json | 141 +++++++++++++++++++++++++++++++++ spec/schemas/ruby.json | 133 +++++++++++++++++++++++++++++++ 4 files changed, 344 insertions(+), 3 deletions(-) create mode 100644 spec/schema_validation_spec.rb create mode 100644 spec/schemas/gem.json create mode 100644 spec/schemas/ruby.json diff --git a/Gemfile b/Gemfile index 2e7b2dab57..b547f12aa6 100644 --- a/Gemfile +++ b/Gemfile @@ -1,9 +1,10 @@ source 'https://rubygems.org' gem 'rake' -gem 'faraday', '~> 2.0' -gem 'kwalify', '~> 0.1' -gem 'rspec', '~> 3.0' +gem 'faraday', '~> 2.0' +gem 'kwalify', '~> 0.1' +gem 'json_schemer', '~> 2.0' +gem 'rspec', '~> 3.0' group :development do gem 'pry' diff --git a/spec/schema_validation_spec.rb b/spec/schema_validation_spec.rb new file mode 100644 index 0000000000..102467881d --- /dev/null +++ b/spec/schema_validation_spec.rb @@ -0,0 +1,66 @@ +require 'spec_helper' + +require 'json_schemer' +require 'yaml' + +SCHEMAS_DIR = File.join(ROOT, 'spec', 'schemas') + +def schemer_for(schema_path) + JSONSchemer.schema( + JSON.parse(File.read(schema_path)), + meta_schema: 'https://json-schema.org/draft/2020-12/schema' + ) +end + +def normalize_for_json(value) + case value + when Hash + value.transform_values { |v| normalize_for_json(v) } + when Array + value.map { |v| normalize_for_json(v) } + when Date + value.iso8601 + else + value + end +end + +def format_errors(errors) + errors.map do |e| + pointer = e['data_pointer'].to_s.empty? ? '' : e['data_pointer'] + + "↳ #{pointer}: #{e['error']}" + end.join("\n") +end + +GEM_SCHEMER = schemer_for(File.join(SCHEMAS_DIR, 'gem.json')) +RUBY_SCHEMER = schemer_for(File.join(SCHEMAS_DIR, 'ruby.json')) + +shared_examples 'conforming schema' do |glob:, schemer:| + Dir.glob(File.join(ROOT, glob)).sort.each do |path| + filename = path.split('/')[-2..].join('/') + + it "#{filename} conforms to schema" do + data = normalize_for_json(YAML.safe_load_file(path, permitted_classes: [Date])) + errors = schemer.validate(data).to_a + + expect(errors).to be_empty, lambda { + "#{filename}\n#{format_errors(errors)}" + } + end + end +end + +describe 'JSON Schema validation' do + describe 'for gems' do + include_examples 'conforming schema', + glob: 'gems/*/*.yml', + schemer: GEM_SCHEMER + end + + describe 'for rubies' do + include_examples 'conforming schema', + glob: 'rubies/*/*.yml', + schemer: RUBY_SCHEMER + end +end diff --git a/spec/schemas/gem.json b/spec/schemas/gem.json new file mode 100644 index 0000000000..e4fabe7934 --- /dev/null +++ b/spec/schemas/gem.json @@ -0,0 +1,141 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/rubysec/ruby-advisory-db/schemas/gem.json", + "title": "Ruby gem advisory", + "type": "object", + "additionalProperties": false, + "required": ["gem", "url", "title", "date", "description"], + "anyOf": [ + { "required": ["cve"] }, + { "required": ["osvdb"] }, + { "required": ["ghsa"] } + ], + "properties": { + "gem": { + "type": "string", + "minLength": 1 + }, + "library": { + "type": "string", + "minLength": 1 + }, + "framework": { + "type": "string", + "minLength": 1 + }, + "platform": { + "type": "string", + "minLength": 1 + }, + "cve": { + "type": "string", + "pattern": "^\\d{4}-\\d+$" + }, + "osvdb": { + "type": "integer", + "minimum": 1 + }, + "ghsa": { + "type": "string", + "pattern": "^[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}$" + }, + "url": { + "type": "string", + "pattern": "^https?://", + "not": { "pattern": "^https?://osvdb\\.org" } + }, + "title": { + "type": "string", + "minLength": 1, + "pattern": "^(?:\\S|\\S.*\\S)$" + }, + "date": { + "type": "string", + "format": "date", + "pattern": "^\\d{4}-\\d{2}-\\d{2}$" + }, + "description": { + "type": "string", + "minLength": 1, + "allOf": [ + { "pattern": "\\n" }, + { "not": { "pattern": "\\\\n\\\\n" } }, + { "not": { "pattern": "(#+) PoC" } } + ] + }, + "cvss_v2": { + "type": "number", + "minimum": 0.0, + "maximum": 10.0 + }, + "cvss_v3": { + "type": "number", + "minimum": 0.0, + "maximum": 10.0 + }, + "cvss_v4": { + "type": "number", + "minimum": 0.0, + "maximum": 10.0 + }, + "unaffected_versions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^(?:<=|<|>=|>|~>|=) [0-9A-Za-z.\\-]+(?:, (?:<=|<|>=|>|~>|=) [0-9A-Za-z.\\-]+)?$" + } + }, + "patched_versions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^(?:<=|<|>=|>|~>|=) [0-9A-Za-z.\\-]+(?:, (?:<=|<|>=|>|~>|=) [0-9A-Za-z.\\-]+)?$" + } + }, + "related": { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "cve": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^\\d{4}-\\d+$" + } + }, + "ghsa": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}$" + } + }, + "osvdb": { + "type": "array", + "minItems": 1, + "items": { + "type": "integer", + "minimum": 1 + } + }, + "url": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^https?://" + } + } + } + }, + "notes": { + "type": "string", + "minLength": 1 + } + } +} diff --git a/spec/schemas/ruby.json b/spec/schemas/ruby.json new file mode 100644 index 0000000000..0fd0747f90 --- /dev/null +++ b/spec/schemas/ruby.json @@ -0,0 +1,133 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/rubysec/ruby-advisory-db/schemas/ruby.json", + "title": "Ruby implementation advisory", + "type": "object", + "additionalProperties": false, + "required": ["engine", "url", "title", "date", "description"], + "anyOf": [ + { "required": ["cve"] }, + { "required": ["osvdb"] }, + { "required": ["ghsa"] } + ], + "properties": { + "engine": { + "type": "string", + "enum": ["ruby", "jruby", "mruby", "mrubyc", "rbx", "truffleruby"] + }, + "platform": { + "type": "string", + "minLength": 1 + }, + "cve": { + "type": "string", + "pattern": "^\\d{4}-\\d+$" + }, + "osvdb": { + "type": "integer", + "minimum": 1 + }, + "ghsa": { + "type": "string", + "pattern": "^[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}$" + }, + "url": { + "type": "string", + "pattern": "^https?://", + "not": { "pattern": "^https?://osvdb\\.org" } + }, + "title": { + "type": "string", + "minLength": 1, + "pattern": "^(?:\\S|\\S.*\\S)$" + }, + "date": { + "type": "string", + "format": "date", + "pattern": "^\\d{4}-\\d{2}-\\d{2}$" + }, + "description": { + "type": "string", + "minLength": 1, + "allOf": [ + { "pattern": "\\n" }, + { "not": { "pattern": "\\\\n\\\\n" } }, + { "not": { "pattern": "(#+) PoC" } } + ] + }, + "cvss_v2": { + "type": "number", + "minimum": 0.0, + "maximum": 10.0 + }, + "cvss_v3": { + "type": "number", + "minimum": 0.0, + "maximum": 10.0 + }, + "cvss_v4": { + "type": "number", + "minimum": 0.0, + "maximum": 10.0 + }, + "unaffected_versions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^(?:<=|<|>=|>|~>|=) [0-9A-Za-z.\\-]+(?:, (?:<=|<|>=|>|~>|=) [0-9A-Za-z.\\-]+)?$" + } + }, + "patched_versions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^(?:<=|<|>=|>|~>|=) [0-9A-Za-z.\\-]+(?:, (?:<=|<|>=|>|~>|=) [0-9A-Za-z.\\-]+)?$" + } + }, + "related": { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "cve": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^\\d{4}-\\d+$" + } + }, + "ghsa": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}$" + } + }, + "osvdb": { + "type": "array", + "minItems": 1, + "items": { + "type": "integer", + "minimum": 1 + } + }, + "url": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^https?://" + } + } + } + }, + "notes": { + "type": "string", + "minLength": 1 + } + } +} From c9a9e750de637ed7a293dbce9a3c2ad55c8f9f89 Mon Sep 17 00:00:00 2001 From: Dennis Paagman Date: Sun, 17 May 2026 19:51:51 +0200 Subject: [PATCH 2/2] Fix validation errors tagged by json schema --- gems/bootstrap-sass/CVE-2018-14042.yml | 2 +- gems/httparty/CVE-2025-68696.yml | 38 -------------------------- gems/nokogiri/GHSA-5w6v-399v-w3cc.yml | 4 +-- gems/nokogiri/GHSA-mrxw-mxhj-p664.yml | 4 +-- gems/omniauth-saml/CVE-2024-45409.yml | 5 ++-- gems/rack-session/CVE-2025-46336.yml | 2 +- gems/rack/CVE-2025-32441.yml | 2 +- gems/rdoc/CVE-2024-27281.yml | 2 +- gems/rexml/CVE-2024-39908.yml | 2 +- gems/rmagick/CVE-2023-5349.yml | 2 +- gems/sidekiq/CVE-2024-32887.yml | 2 +- rubies/jruby/CVE-2019-16254.yml | 2 +- rubies/ruby/CVE-2005-1992.yml | 2 +- rubies/ruby/CVE-2017-17405.yml | 2 +- 14 files changed, 16 insertions(+), 55 deletions(-) diff --git a/gems/bootstrap-sass/CVE-2018-14042.yml b/gems/bootstrap-sass/CVE-2018-14042.yml index 920e3a9952..cf7ccc6b34 100644 --- a/gems/bootstrap-sass/CVE-2018-14042.yml +++ b/gems/bootstrap-sass/CVE-2018-14042.yml @@ -18,7 +18,7 @@ patched_versions: - ">= 4.1.2" related: cve: - - CVE-2018-14041 + - 2018-14041 url: - https://nvd.nist.gov/vuln/detail/CVE-2018-14042 - https://github.com/twbs/bootstrap/issues/26423 diff --git a/gems/httparty/CVE-2025-68696.yml b/gems/httparty/CVE-2025-68696.yml index 2b1c5e1af4..4e6aa50e1c 100644 --- a/gems/httparty/CVE-2025-68696.yml +++ b/gems/httparty/CVE-2025-68696.yml @@ -55,44 +55,6 @@ description: | Also, Python's `urljoin` function has documented a warning about similar behavior: - ## PoC - - Follow these steps to reproduce the issue: - - 1. Set up two simple HTTP servers. - - ```bash - mkdir /tmp/server1 /tmp/server2 - echo "this is server1" > /tmp/server1/index.html - echo "this is server2" > /tmp/server2/index.html - python -m http.server -d /tmp/server1 10001 & - python -m http.server -d /tmp/server2 10002 & - ``` - - 2. Create a script (for example, `main.rb`): - - ```rb - require 'httparty' - - class Client - include HTTParty - base_uri 'http://localhost:10001' - end - - data = Client.get('http://localhost:10002').body - puts data - ``` - - 3. Run the script: - - ```bash - $ ruby main.rb - this is server2 - ``` - - Although `base_uri` is set to `http://localhost:10001/`, httparty sends the request to `http://localhost:10002/`. - - ## Impact - Leakage of credentials: If an absolute URL is provided, any API keys or credentials configured in httparty may be exposed to unintended third-party hosts. diff --git a/gems/nokogiri/GHSA-5w6v-399v-w3cc.yml b/gems/nokogiri/GHSA-5w6v-399v-w3cc.yml index 7bb4fa126c..59a2777568 100644 --- a/gems/nokogiri/GHSA-5w6v-399v-w3cc.yml +++ b/gems/nokogiri/GHSA-5w6v-399v-w3cc.yml @@ -50,8 +50,8 @@ patched_versions: - ">= 1.18.8" related: cve: - - CVE-2025-32414 - - CVE-2025-32415 + - 2025-32414 + - 2025-32415 url: - https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-5w6v-399v-w3cc - https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.13.8 diff --git a/gems/nokogiri/GHSA-mrxw-mxhj-p664.yml b/gems/nokogiri/GHSA-mrxw-mxhj-p664.yml index 291f878e2b..dead10c775 100644 --- a/gems/nokogiri/GHSA-mrxw-mxhj-p664.yml +++ b/gems/nokogiri/GHSA-mrxw-mxhj-p664.yml @@ -40,5 +40,5 @@ related: - https://gitlab.gnome.org/GNOME/libxslt/-/issues/128 - https://github.com/advisories/GHSA-mrxw-mxhj-p664 cve: - - https://nvd.nist.gov/vuln/detail/CVE-2024-55549 - - https://nvd.nist.gov/vuln/detail/CVE-2025-24855 + - 2024-55549 + - 2025-24855 diff --git a/gems/omniauth-saml/CVE-2024-45409.yml b/gems/omniauth-saml/CVE-2024-45409.yml index a01e160ed2..9c96343693 100644 --- a/gems/omniauth-saml/CVE-2024-45409.yml +++ b/gems/omniauth-saml/CVE-2024-45409.yml @@ -20,9 +20,8 @@ patched_versions: - ">= 2.2.1" related: ghsa: - - https://github.com/omniauth/omniauth-saml/security/advisories/GHSA-cvp8-5r8g-fhvq - - https://github.com/SAML-Toolkits/ruby-saml/security/advisories/GHSA-jw9c-mfg7-9rx2 - - https://github.com/advisories/GHSA-cvp8-5r8g-fhvq + - cvp8-5r8g-fhvq + - jw9c-mfg7-9rx2 url: - https://github.com/omniauth/omniauth-saml/commit/4274e9d57e65f2dcaae4aa3b2accf831494f2ddd - https://github.com/omniauth/omniauth-saml/commit/6c681fd082ab3daf271821897a40ab3417382e29 diff --git a/gems/rack-session/CVE-2025-46336.yml b/gems/rack-session/CVE-2025-46336.yml index 207161a400..bfcf88a811 100644 --- a/gems/rack-session/CVE-2025-46336.yml +++ b/gems/rack-session/CVE-2025-46336.yml @@ -50,7 +50,7 @@ patched_versions: - ">= 2.1.1" related: ghsa: - - https://github.com/rack/rack/security/advisories/GHSA-vpfw-47h7-xj4g + - vpfw-47h7-xj4g url: - https://nvd.nist.gov/vuln/detail/CVE-2025-46336 - https://github.com/rack/rack-session/commit/c28c4a8c1861d814e09f2ae48264ac4c40be2d3b diff --git a/gems/rack/CVE-2025-32441.yml b/gems/rack/CVE-2025-32441.yml index c7c7615f20..d5f8299ef9 100644 --- a/gems/rack/CVE-2025-32441.yml +++ b/gems/rack/CVE-2025-32441.yml @@ -48,7 +48,7 @@ patched_versions: - ">= 2.2.14" related: ghsa: - - https://github.com/rack/rack-session/security/advisories/GHSA-9j94-67jr-4cqj + - 9j94-67jr-4cqj url: - https://nvd.nist.gov/vuln/detail/CVE-2025-32441 - https://github.com/rack/rack/security/advisories/GHSA-vpfw-47h7-xj4g diff --git a/gems/rdoc/CVE-2024-27281.yml b/gems/rdoc/CVE-2024-27281.yml index e6512ce32b..5ddaf1f98c 100644 --- a/gems/rdoc/CVE-2024-27281.yml +++ b/gems/rdoc/CVE-2024-27281.yml @@ -33,4 +33,4 @@ cvss_v3: 4.5 patched_versions: - "~> 6.3.4, >= 6.3.4.1" - "~> 6.4.1, >= 6.4.1.1" - - ">= 6.5.1.1" + - ">= 6.5.1.1" diff --git a/gems/rexml/CVE-2024-39908.yml b/gems/rexml/CVE-2024-39908.yml index 1f98919311..0bb6b7156f 100644 --- a/gems/rexml/CVE-2024-39908.yml +++ b/gems/rexml/CVE-2024-39908.yml @@ -33,7 +33,7 @@ patched_versions: - ">= 3.3.2" related: ghsa: - - https://github.com/ruby/rexml/security/advisories/GHSA-vg3r-rm7w-2xgh + - vg3r-rm7w-2xgh url: - https://www.ruby-lang.org/en/news/2024/07/16/dos-rexml-cve-2024-39908 - https://github.com/ruby/rexml/security/advisories/GHSA-4xqq-m2hx-25v8 diff --git a/gems/rmagick/CVE-2023-5349.yml b/gems/rmagick/CVE-2023-5349.yml index 11c149bc0b..bcdd210d20 100644 --- a/gems/rmagick/CVE-2023-5349.yml +++ b/gems/rmagick/CVE-2023-5349.yml @@ -14,7 +14,7 @@ patched_versions: - ">= 5.3.0" related: ghsa: - - https://github.com/advisories/GHSA-j6x7-7g72-8ww2 + - j6x7-7g72-8ww2 url: - https://nvd.nist.gov/vuln/detail/CVE-2023-5349 - https://github.com/rmagick/rmagick/issues/1401 diff --git a/gems/sidekiq/CVE-2024-32887.yml b/gems/sidekiq/CVE-2024-32887.yml index 4f2876376d..28aa799233 100644 --- a/gems/sidekiq/CVE-2024-32887.yml +++ b/gems/sidekiq/CVE-2024-32887.yml @@ -1,7 +1,7 @@ --- gem: sidekiq cve: 2024-32887 -ghsa: GHSA-q655-3pj8-9fxq +ghsa: q655-3pj8-9fxq url: https://github.com/sidekiq/sidekiq/security/advisories/GHSA-q655-3pj8-9fxq title: Reflected XSS in Metrics Web Page date: 2024-04-26 diff --git a/rubies/jruby/CVE-2019-16254.yml b/rubies/jruby/CVE-2019-16254.yml index 0238efa016..015ed5b7ef 100644 --- a/rubies/jruby/CVE-2019-16254.yml +++ b/rubies/jruby/CVE-2019-16254.yml @@ -19,7 +19,7 @@ patched_versions: - ">= 9.2.12.0" related: cve: - - CVE-2017-17742 + - 2017-17742 url: - https://nvd.nist.gov/vuln/detail/CVE-2019-16254 - https://github.com/jruby/jruby/releases/tag/9.2.12.0 diff --git a/rubies/ruby/CVE-2005-1992.yml b/rubies/ruby/CVE-2005-1992.yml index 04c7a4b6d6..72bc8a1772 100644 --- a/rubies/ruby/CVE-2005-1992.yml +++ b/rubies/ruby/CVE-2005-1992.yml @@ -24,4 +24,4 @@ related: - http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=315064 - http://www.debian.org/security/2005/dsa-748 - http://www.kb.cert.org/vuls/id/684913 - - http:/https://github.com/advisories/GHSA-vf66-crpm-448h + - https://github.com/advisories/GHSA-vf66-crpm-448h diff --git a/rubies/ruby/CVE-2017-17405.yml b/rubies/ruby/CVE-2017-17405.yml index 56b54b4f07..63aba07238 100644 --- a/rubies/ruby/CVE-2017-17405.yml +++ b/rubies/ruby/CVE-2017-17405.yml @@ -1,7 +1,7 @@ --- engine: ruby cve: 2017-17405 -ghsa: https://github.com/advisories/GHSA-q23r-c9rf-97q3 +ghsa: q23r-c9rf-97q3 url: https://nvd.nist.gov/vuln/detail/CVE-2017-17405 title: Command injection vulnerability in Net::FTP date: 2017-12-14