diff --git a/lib/fluent/vulnerability_checker.rb b/lib/fluent/vulnerability_checker.rb index 6812497..68f8181 100644 --- a/lib/fluent/vulnerability_checker.rb +++ b/lib/fluent/vulnerability_checker.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'yaml' + require 'fluent/config' require 'fluent/env' @@ -7,21 +9,25 @@ module Fluent class VulnerabilityChecker CHUNK_ID_PLACEHOLDER_PATTERN = /\$\{chunk_id\}/ PLACEHOLDER_PATTERN = /\$\{.*?\}/ + MESSAGES_PATH = File.join(__dir__, 'vulnerability_checker', 'messages.yaml') class Rule - def initialize(plugin_categories, plugin_name = nil, &condition_proc) + attr_reader :cve + + def initialize(cve, plugin_categories, plugin_name = nil, &condition_proc) + @cve = cve @plugin_categories = Array(plugin_categories) @plugin_name = plugin_name @condition_proc = condition_proc end - def register_report_message(&report_proc) - @report_proc = report_proc + def register_state_message(&state_proc) + @state_proc = state_proc self end - def report(element) - @report_proc&.call(element) + def state(element) + @state_proc&.call(element) end def safe?(element) @@ -33,184 +39,91 @@ def safe?(element) end end + class Report + # Width of the "* State: " label. Continuation lines are aligned with it. + STATE_INDENT = ' ' * 14 + # Width of the " * EN: " label. + TEXT_INDENT = ' ' * 8 + + def initialize(messages_path = MESSAGES_PATH) + @messages = YAML.load_file(messages_path) + end + + def render(rule, element) + message = @messages.fetch(rule.cve) + state = rule.state(element) + + lines = [ + "# #{message['title']}", + "* Severity: #{message['severity']}", + "* CVSS Score: #{message['cvss']}", + "* Location: <#{element.name}> - @type #{element['@type']}" + ] + if state + lines << "* State: #{state}" + lines << "#{STATE_INDENT}#{align(message['note'], STATE_INDENT)}" if message['note'] + end + lines << '* Description:' + lines.concat(bilingual(message['description'])) + lines << '* Workaround:' + lines.concat(bilingual(message['workaround'])) + lines.join("\n") + end + + private + + def bilingual(texts) + ['en', 'ja'].map { |lang| " * #{lang.upcase}: #{align(texts.fetch(lang), TEXT_INDENT)}" } + end + + def align(text, indent) + text.strip.gsub("\n", "\n#{indent}") + end + end + attr_reader :vulnerabilities # for test def initialize @vulnerabilities = 0 + @report = Report.new @rules = [] # Fluentd: RCE via ${tag} in file in output/buffer/secondary/store sections - @rules << Rule.new(['match', 'buffer', 'secondary', 'store'], 'file') { |element| + @rules << Rule.new('CVE-2026-44024', ['match', 'buffer', 'secondary', 'store'], 'file') { |element| # replace the safe ${chunk_id} with an empty string to clear it, and check if the remaining string contains ${...} element['path']&.gsub(CHUNK_ID_PLACEHOLDER_PATTERN, '')&.match?(PLACEHOLDER_PATTERN) - }.register_report_message do |element| - <<~"MSG" - # Remote Code Execution (RCE) via Arbitrary File Write in Dynamic Placeholder - * Severity: Critical - * CVSS Score: 10.0 - * Location: <#{element.name}> - @type #{element['@type']} - * State: path = '#{element['path']}' - * Description: - * EN: If the ${tag} placeholder is used in the path parameter of the file output plugin, there is a risk that - an attacker could write files to arbitrary paths, potentially leading to RCE. - * JA: pathでプレースホルダーにtagを指定している場合、設定ファイルの書き方や実行権限が不適切だと、任意のパスに - ファイルを書き込まれ、リモートからコード実行可能になる危険があります。 - * Workaround: - * EN: If you cannot immediately update the package, apply mitigations such as restricting access, - running with non-root privileges, modifying the configuration file, or removing untrusted tags. - * JA: すぐにパッケージを更新できない場合、アクセスの制限、非root権限での実行、設定ファイルの修正、信頼できない - tagを除去するなどの緩和策を適用してください。 - MSG - end + }.register_state_message { |element| "path = '#{element['path']}'" } # Fluentd: RCE via ${tag} in secondary_file - @rules << Rule.new('secondary', 'secondary_file') { |element| + @rules << Rule.new('CVE-2026-44024', 'secondary', 'secondary_file') { |element| # replace the safe ${chunk_id} with an empty string to clear it, and check if the remaining string contains ${...} element['directory']&.gsub(CHUNK_ID_PLACEHOLDER_PATTERN, '')&.match?(PLACEHOLDER_PATTERN) || element['basename']&.gsub(CHUNK_ID_PLACEHOLDER_PATTERN, '')&.match?(PLACEHOLDER_PATTERN) - }.register_report_message do |element| - state_msg = ['directory', 'basename'].map { |k| "#{k} = '#{element[k]}'" if element[k]&.match?(PLACEHOLDER_PATTERN) }.compact.join(', ') - <<~"MSG" - # Remote Code Execution (RCE) via Arbitrary File Write in Dynamic Placeholder - * Severity: Critical - * CVSS Score: 10.0 - * Location: <#{element.name}> - @type #{element['@type']} - * State: #{state_msg} - * Description: - * EN: If the ${tag} placeholder is used in the directory or basename parameter of the secondary_file plugin, - there is a risk that an attacker could write files to arbitrary paths, potentially leading to RCE. - * JA: directoryまたはbasenameでプレースホルダーにtagを指定している場合、設定ファイルの書き方や実行権限が不適切だと、任意のパスに - ファイルを書き込まれ、リモートからコード実行可能になる危険があります。 - * Workaround: - * EN: If you cannot immediately update the package, apply mitigations such as restricting access, - running with non-root privileges, modifying the configuration file, or removing untrusted tags. - * JA: すぐにパッケージを更新できない場合、アクセスの制限、非root権限での実行、設定ファイルの修正、信頼できない - tagを除去するなどの緩和策を適用してください。 - MSG + }.register_state_message do |element| + ['directory', 'basename'].map { |k| "#{k} = '#{element[k]}'" if element[k]&.match?(PLACEHOLDER_PATTERN) }.compact.join(', ') end # Fluentd: Exposure of Sensitive Information - @rules << Rule.new('source', 'monitor_agent') { |element| element['bind'].nil? || element['bind'] == '0.0.0.0' }.register_report_message do |element| - <<~"MSG" - # Exposure of Sensitive Information via Monitor Agent API - * Severity: High - * CVSS Score: 7.5 - * Location: <#{element.name}> - @type #{element['@type']} - * State: bind = '#{element['bind'] || 'default'}'. - (Note: In Fluentd 1.19.2 and earlier, the default value of bind is 0.0.0.0.) - * Description: - * EN: monitor_agent is exposed externally, allowing attackers to read Fluentd configuration details via its API. - * JA: monitor_agentによって公開されているAPIを悪用して、Fluentdの設定内容を読み取られる危険性があります。 - * Workaround: - * EN: If you cannot immediately update the package, apply mitigations such as restricting access, - or allowing access only from localhost. - * JA: すぐにパッケージを更新できない場合、アクセスの制限、ローカルホストからのみのアクセスを受け付けるなどの - 緩和策を適用してください。 - MSG - end + @rules << Rule.new('CVE-2026-44025', 'source', 'monitor_agent') { |element| + element['bind'].nil? || element['bind'] == '0.0.0.0' + }.register_state_message { |element| "bind = '#{element['bind'] || 'default'}'." } # Fluentd: DoS via Gzip Decompression in http input plugin - @rules << Rule.new('source', 'http') { |element| true }.register_report_message do |element| - <<~"MSG" - # Denial of Service (DoS) via Gzip Decompression Bomb - * Severity: High - * CVSS Score: 7.5 - * Location: <#{element.name}> - @type #{element['@type']} - * Description: - * EN: Sending maliciously crafted gzip-compressed data to Fluentd can consume excessive memory during - decompression, potentially causing it to crash. - * JA: 細工したgzip圧縮データをFluentdへと送りつけることで、展開時に大量のメモリを消費させてFluentdをクラッシュ - する危険性があります。 - * Workaround: - * EN: If you cannot immediately update the package, apply mitigations such as restricting access, or enforcing - size limits when decompressing content using a reverse proxy. - * JA: すぐにパッケージを更新できない場合、アクセスの制限、リバースプロキシ等を用いたGZIP展開時のサイズ制限等の - 緩和策を適用してください。 - MSG - end + @rules << Rule.new('CVE-2026-44160', 'source', 'http') { |element| true } # Fluentd: DoS via Gzip Decompression in forward input plugin - @rules << Rule.new('source', 'forward') { |element| true }.register_report_message do |element| - <<~"MSG" - # Denial of Service (DoS) via Gzip Decompression Bomb - * Severity: High - * CVSS Score: 7.5 - * Location: <#{element.name}> - @type #{element['@type']} - * Description: - * EN: Sending maliciously crafted gzip-compressed data to Fluentd can consume excessive memory during - decompression, potentially causing it to crash. - * JA: 細工したgzip圧縮データを受信することで、展開時に大量のメモリを消費してFluentdがクラッシュする危険性が - あります。 - * Workaround: - * EN: If you cannot immediately update the package, apply mitigations such as restricting access, or enforcing - size limits when decompressing content using a reverse proxy. - * JA: すぐにパッケージを更新できない場合、アクセスの制限、リバースプロキシ等を用いたGZIP展開時のサイズ制限等の - 緩和策を適用してください。 - MSG - end + @rules << Rule.new('CVE-2026-44160', 'source', 'forward') { |element| true } # fluent-plugin-s3: DoS via Gzip Decompression - @rules << Rule.new('source', 's3') { |element| true }.register_report_message do |element| - <<~"MSG" - # Denial of Service (DoS) via Gzip Decompression Bomb - * Severity: Low - * CVSS Score: 2.7 - * Location: <#{element.name}> - @type #{element['@type']} - * Description: - * EN: Sending maliciously crafted gzip-compressed data from S3 to Fluentd can consume excessive memory when - processing requests, potentially causing it to crash. - * JA: 細工したgzip圧縮データをS3から受信することで、展開時に大量のメモリを消費してFluentdがクラッシュする - 危険性があります。 - * Workaround: - * EN: If you cannot immediately update the package, apply mitigations such as restricting access, or enforcing - size limits when decompressing content using a reverse proxy. - * JA: すぐにパッケージを更新できない場合、アクセスの制限、リバースプロキシ等を用いたGZIP展開時のサイズ制限等の - 緩和策を適用してください。 - MSG - end + @rules << Rule.new('CVE-2026-44162', 'source', 's3') { |element| true } # fluent-plugin-opentelemetry: DoS - @rules << Rule.new('source', 'opentelemetry') { |element| true }.register_report_message do |element| - <<~"MSG" - # Denial of Service (DoS) via Gzip Decompression Bomb or Malicious HTTP Requests - * Severity: Moderate - * CVSS Score: 5.3 - * Location: <#{element.name}> - @type #{element['@type']} - * Description: - * EN: Sending maliciously crafted gzip-compressed data to Fluentd can consume excessive memory when processing - requests, potentially causing it to crash. - * JA: 細工したgzip圧縮データやHTTPリクエストを受信することで、リクエスト処理時に大量のメモリを消費してFluentdが - クラッシュする危険性があります。 - * Workaround: - * EN: If you cannot immediately update the package, apply mitigations such as restricting access, or enforcing - size limits when processing requests using a reverse proxy. - * JA: すぐにパッケージを更新できない場合、アクセスの制限、リバースプロキシ等を用いたリクエストサイズ制限等の - 緩和策を適用してください。 - MSG - end + @rules << Rule.new('CVE-2026-44163', 'source', 'opentelemetry') { |element| true } # Fluentd: SSRF via ${endpoint} in http output plugin - @rules << Rule.new('match', 'http') { |element| element['endpoint']&.match?(%r[https?://[^/]*\$\{]) }.register_report_message do |element| - <<~"MSG" - # Server-Side Request Forgery (SSRF) via Placeholder Expansion in out_http - * Severity: Moderate - * CVSS Score: 5.8 - * Location: <#{element.name}> - @type #{element['@type']} - * Description: - * EN: When out_http determines destination servers for data transmission based on tags, this vulnerability - allows attackers to manipulate data transmission by sending crafted data, resulting in data being sent - to servers other than the intended ones. - * JA: out_httpでデータを別のサーバーに送る際の送信先をタグから決定している場合、細工したデータを送りつけられると、 - 本来の意図とは異なるサーバーへとデータを送信してしまうことが可能な脆弱性です。 - * Workaround: - * EN: If you cannot immediately update the package, apply mitigation measures such as: - * not dynamically setting hostnames with placeholders - * restricting access from untrusted networks - * allowing only specific hosts - * JA: すぐにパッケージを更新できない場合、プレースホルダーでホスト名を動的に設定しない、信頼できない - ネットワークからのアクセスの制限、特定のホストのみ許可するなどの緩和策を適用してください。 - MSG - end + @rules << Rule.new('CVE-2026-44161', 'match', 'http') { |element| + element['endpoint']&.match?(%r[https?://[^/]*\$\{]) + } end def validate(config_path) @@ -227,7 +140,7 @@ def check_element(element) @rules.each do |rule| unless rule.safe?(element) @vulnerabilities += 1 - puts rule.report(element) + puts @report.render(rule, element) puts "=" * 115 end end diff --git a/lib/fluent/vulnerability_checker/messages.yaml b/lib/fluent/vulnerability_checker/messages.yaml new file mode 100644 index 0000000..daf10db --- /dev/null +++ b/lib/fluent/vulnerability_checker/messages.yaml @@ -0,0 +1,120 @@ +# Message catalog for the vulnerabilities this tool detects. +# +# Each key should be the CVE ID of the advisory. +--- +CVE-2026-44024: + title: Remote Code Execution (RCE) via Arbitrary File Write in Dynamic Placeholder + severity: Critical + cvss: 10.0 + description: + en: | + If the ${tag} placeholder is used in a file path parameter of the file or secondary_file output plugin, + there is a risk that an attacker could write files to arbitrary paths, potentially leading to RCE. + ja: | + ファイルの出力先パスでプレースホルダーにtagを指定している場合、設定ファイルの書き方や実行権限が不適切だと、 + 任意のパスにファイルを書き込まれ、リモートからコード実行可能になる危険があります。 + workaround: + en: | + If you cannot immediately update the package, apply mitigations such as restricting access, + running with non-root privileges, modifying the configuration file, or removing untrusted tags. + ja: | + すぐにパッケージを更新できない場合、アクセスの制限、非root権限での実行、設定ファイルの修正、信頼できない + tagを除去するなどの緩和策を適用してください。 + +CVE-2026-44025: + title: Exposure of Sensitive Information via Monitor Agent API + severity: High + cvss: 7.5 + note: | + (Note: In Fluentd 1.19.2 and earlier, the default value of bind is 0.0.0.0.) + description: + en: | + monitor_agent is exposed externally, allowing attackers to read Fluentd configuration details via its API. + ja: | + monitor_agentによって公開されているAPIを悪用して、Fluentdの設定内容を読み取られる危険性があります。 + workaround: + en: | + If you cannot immediately update the package, apply mitigations such as restricting access, + or allowing access only from localhost. + ja: | + すぐにパッケージを更新できない場合、アクセスの制限、ローカルホストからのみのアクセスを受け付けるなどの + 緩和策を適用してください。 + +CVE-2026-44160: + title: Denial of Service (DoS) via Gzip Decompression Bomb + severity: High + cvss: 7.5 + description: + en: | + Sending maliciously crafted gzip-compressed data to Fluentd can consume excessive memory during + decompression, potentially causing it to crash. + ja: | + 細工したgzip圧縮データをFluentdへと送りつけることで、展開時に大量のメモリを消費させてFluentdをクラッシュ + する危険性があります。 + workaround: + en: | + If you cannot immediately update the package, apply mitigations such as restricting access, or enforcing + size limits when decompressing content using a reverse proxy. + ja: | + すぐにパッケージを更新できない場合、アクセスの制限、リバースプロキシ等を用いたGZIP展開時のサイズ制限等の + 緩和策を適用してください。 + +CVE-2026-44161: + title: Server-Side Request Forgery (SSRF) via Placeholder Expansion in out_http + severity: Moderate + cvss: 5.8 + description: + en: | + When out_http determines destination servers for data transmission based on tags, this vulnerability + allows attackers to manipulate data transmission by sending crafted data, resulting in data being sent + to servers other than the intended ones. + ja: | + out_httpでデータを別のサーバーに送る際の送信先をタグから決定している場合、細工したデータを送りつけられると、 + 本来の意図とは異なるサーバーへとデータを送信してしまうことが可能な脆弱性です。 + workaround: + en: | + If you cannot immediately update the package, apply mitigation measures such as: + * not dynamically setting hostnames with placeholders + * restricting access from untrusted networks + * allowing only specific hosts + ja: | + すぐにパッケージを更新できない場合、プレースホルダーでホスト名を動的に設定しない、信頼できない + ネットワークからのアクセスの制限、特定のホストのみ許可するなどの緩和策を適用してください。 + +CVE-2026-44162: + title: Denial of Service (DoS) via Gzip Decompression Bomb + severity: Low + cvss: 2.7 + description: + en: | + Sending maliciously crafted gzip-compressed data from S3 to Fluentd can consume excessive memory when + processing requests, potentially causing it to crash. + ja: | + 細工したgzip圧縮データをS3から受信することで、展開時に大量のメモリを消費してFluentdがクラッシュする + 危険性があります。 + workaround: + en: | + If you cannot immediately update the package, apply mitigations such as restricting access, or enforcing + size limits when decompressing content using a reverse proxy. + ja: | + すぐにパッケージを更新できない場合、アクセスの制限、リバースプロキシ等を用いたGZIP展開時のサイズ制限等の + 緩和策を適用してください。 + +CVE-2026-44163: + title: Denial of Service (DoS) via Gzip Decompression Bomb or Malicious HTTP Requests + severity: Moderate + cvss: 5.3 + description: + en: | + Sending maliciously crafted gzip-compressed data to Fluentd can consume excessive memory when processing + requests, potentially causing it to crash. + ja: | + 細工したgzip圧縮データやHTTPリクエストを受信することで、リクエスト処理時に大量のメモリを消費してFluentdが + クラッシュする危険性があります。 + workaround: + en: | + If you cannot immediately update the package, apply mitigations such as restricting access, or enforcing + size limits when processing requests using a reverse proxy. + ja: | + すぐにパッケージを更新できない場合、アクセスの制限、リバースプロキシ等を用いたリクエストサイズ制限等の + 緩和策を適用してください。