VYPR
Moderate severityOSV Advisory· Published Jan 4, 2024· Updated Nov 29, 2025

httparty Multipart/Form-Data Request Tampering Vulnerability

CVE-2024-22049

Description

httparty before 0.21.0 is vulnerable to an assumed-immutable web parameter vulnerability. A remote and unauthenticated attacker can provide a crafted filename parameter during multipart/form-data uploads which could result in attacker controlled filenames being written.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

httparty before 0.21.0 allows remote unauthenticated attackers to inject arbitrary filenames during multipart/form-data uploads, potentially overwriting form fields or altering file extensions.

The vulnerability lies in the generate_multipart method of httparty's request body handling. The filename parameter in the Content-Disposition header is not escaped, allowing an attacker to inject double quotes and newline characters. This leads to the generation of a malformed header that can introduce additional form fields or alter the file extension [2][4].

A remote, unauthenticated attacker can exploit this by crafting a filename string that, when embedded in the multipart/form-data body, results in a Content-Disposition header with multiple name attributes or a modified filename extension. For example, a filename like "overwrite_name_field_and_extension.sh"; name="foo"; dummy=".txt" can cause the parser to interpret additional fields or change the expected file type. The attack has been confirmed to work against frameworks such as Spring (Java), Ktor (Kotlin), and Ruby on Rails (Ruby) [2].

Impact includes the ability to manipulate form data, potentially overwriting other form fields (e.g., enabling a disabled field) or changing the file extension of an uploaded file, which could lead to arbitrary file upload or impersonation of other parameters [2].

The issue was resolved in httparty version 0.21.0 by properly escaping double quotes, carriage returns, and line feeds according to the WHATWG HTML specification. The fix adds a replacement table that encodes these characters as %22, %0D, and %0A respectively [3]. Users are advised to upgrade to 0.21.0 or later to mitigate the vulnerability [1].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
httpartyRubyGems
< 0.21.00.21.0

Affected products

2

Patches

1
cdb45a678c43

Merge pull request from GHSA-5pq7-52mg-hr42

https://github.com/jnunemaker/httpartyJohn NunemakerDec 30, 2022via ghsa
2 files changed · +40 1
  • lib/httparty/request/body.rb+8 1 modified
    @@ -32,6 +32,13 @@ def multipart?
     
           private
     
    +      # https://html.spec.whatwg.org/#multipart-form-data
    +      MULTIPART_FORM_DATA_REPLACEMENT_TABLE = {
    +        '"'  => '%22',
    +        "\r" => '%0D',
    +        "\n" => '%0A'
    +      }.freeze
    +
           def generate_multipart
             normalized_params = params.flat_map { |key, value| HashConversions.normalize_keys(key, value) }
     
    @@ -40,7 +47,7 @@ def generate_multipart
               memo << %(Content-Disposition: form-data; name="#{key}")
               # value.path is used to support ActionDispatch::Http::UploadedFile
               # https://github.com/jnunemaker/httparty/pull/585
    -          memo << %(; filename="#{file_name(value)}") if file?(value)
    +          memo << %(; filename="#{file_name(value).gsub(/["\r\n]/, MULTIPART_FORM_DATA_REPLACEMENT_TABLE)}") if file?(value)
               memo << NEWLINE
               memo << "Content-Type: #{content_type(value)}#{NEWLINE}" if file?(value)
               memo << NEWLINE
    
  • spec/httparty/request/body_spec.rb+32 0 modified
    @@ -105,6 +105,38 @@
     
               it { is_expected.to eq multipart_params }
             end
    +
    +        context 'when file name contains [ " \r \n ]' do
    +          let(:options) { { force_multipart: true } }
    +          let(:some_temp_file) { Tempfile.new(['basefile', '.txt']) }
    +          let(:file_content) { 'test' }
    +          let(:raw_filename) { "dummy=tampering.sh\"; \r\ndummy=a.txt" }
    +          let(:expected_file_name) { 'dummy=tampering.sh%22; %0D%0Adummy=a.txt' }
    +          let(:file) { double(:mocked_action_dispatch, path: some_temp_file.path, original_filename: raw_filename, read: file_content) }
    +          let(:params) do
    +            {
    +              user: {
    +                attachment_file: file,
    +                enabled: true
    +              }
    +            }
    +          end
    +          let(:multipart_params) do
    +            "--------------------------c772861a5109d5ef\r\n" \
    +            "Content-Disposition: form-data; name=\"user[attachment_file]\"; filename=\"#{expected_file_name}\"\r\n" \
    +            "Content-Type: text/plain\r\n" \
    +            "\r\n" \
    +            "test\r\n" \
    +            "--------------------------c772861a5109d5ef\r\n" \
    +            "Content-Disposition: form-data; name=\"user[enabled]\"\r\n" \
    +            "\r\n" \
    +            "true\r\n" \
    +            "--------------------------c772861a5109d5ef--\r\n"
    +          end
    +
    +          it { is_expected.to eq multipart_params }
    +
    +        end
           end
         end
       end
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

10

News mentions

0

No linked articles in our index yet.