docusealco/docuseal · error · Submitters::NormalizeValues::InvalidDefaultValue

File type '.#{extension}' is not allowed.

Error message

File type '.#{extension}' is not allowed.

What it means

Submitters::NormalizeValues#find_or_create_blob_from_url (lib/submitters/normalize_values.rb:282) raises InvalidDefaultValue when the extension of the URL's last path segment (File.extname, downcased) is in Submitters::DANGEROUS_EXTENSIONS. The check runs before any download: it is purely filename-based on the remote URL, so 'https://host/payload.exe' is rejected immediately while extension-less URLs proceed to DownloadUtils with SSRF validation.

Source

Thrown at lib/submitters/normalize_values.rb:282

      checksum = Digest::MD5.base64digest(data)

      blob = find_blob_by_checksum(checksum, account)

      blob || ActiveStorage::Blob.create_and_upload!(
        io: StringIO.new(data),
        filename: "#{type}.png",
        content_type: 'image/png',
        metadata: { analyzed: true, identified: true, width:, height: }
      )
    end

    def find_or_create_blob_from_url(account, url)
      filename = Addressable::URI.parse(url).path.split('/').last.to_s
      extension = File.extname(filename).delete_prefix('.').downcase

      if Submitters::DANGEROUS_EXTENSIONS.include?(extension)
        raise InvalidDefaultValue, "File type '.#{extension}' is not allowed."
      end

      cache_key = [account.id, url].join(':')
      checksum = CHECKSUM_CACHE_STORE.fetch(cache_key)

      blob = find_blob_by_checksum(checksum, account) if checksum

      return blob if blob

      data = DownloadUtils.call(url, validate: true).body

      checksum = Digest::MD5.base64digest(data)

      CHECKSUM_CACHE_STORE.write(cache_key, checksum)

      blob = find_blob_by_checksum(checksum, account)

      blob || ActiveStorage::Blob.create_and_upload!(io: StringIO.new(data), filename:)

View on GitHub (pinned to 004a22c1c8)

Solutions

  1. Point the URL at a safe, allowed document/image resource (pdf, png, jpg, docx...).
  2. If the asset is legitimately named with a dangerous extension, re-host it under a safe filename or bundle it into a zip/pdf and link that.
  3. Rescue Submitters::NormalizeValues::InvalidDefaultValue and surface the message as a 422 so callers see the rejected extension.

Example fix

# before
{ 'default_value' => 'https://cdn.example.com/downloads/setup.exe' }

# after
{ 'default_value' => 'https://cdn.example.com/downloads/instructions.pdf' }
Defensive patterns

Strategy: validation

Validate before calling

# Check the URL's last path segment against the same blocklist
ext = File.extname(URI.parse(url).path.split('/').last.to_s).delete_prefix('.').downcase
raise ArgumentError, "File type '.#{ext}' is not allowed." if Submitters::DANGEROUS_EXTENSIONS.include?(ext)

Try / catch

begin
  Submitters::NormalizeValues.normalize_attachment_value(url, field, account, attachments, purpose: :api)
rescue Submitters::NormalizeValues::InvalidDefaultValue => e
  render json: { error: e.message }, status: :unprocessable_entity
end

Prevention

When it happens

Trigger: An API default_value URL ending in .exe/.sh/.jar/.dll/.apk etc.; URLs with query strings after the dangerous extension (extname still resolves to the last segment); test/probing calls pointing at executable downloads.

Common situations: Integrations pre-filling attachments from asset servers that host both documents and binaries; URL signed-asset filenames retaining the original dangerous extension; users pasting direct download links to installers.

Related errors


AI-assisted analysis of docusealco/docuseal@004a22c1c8 (2026-08-21). Data as JSON: /api/errors/c8b917ef70539cef. Report an issue: GitHub.