{"record":{"id":"d0c2ca9d41e98cf7","repo":"docusealco/docuseal","slug":"file-type-extension-is-not-allowed","errorCode":null,"errorMessage":"File type '.#{extension}' is not allowed.","messagePattern":"File type '\\.#(.+?)' is not allowed\\.","errorType":"validation","errorClass":"Submitters::MaliciousFileExtension","httpStatus":422,"severity":"error","filePath":"lib/submitters.rb","lineNumber":132,"sourceCode":"      return [submitter.submission.combined_document_attachment || Submissions::EnsureCombinedGenerated.call(submitter)]\n    end\n\n    original_documents = submitter.submission.schema_documents.preload(:blob)\n    is_more_than_two_images = original_documents.many?(&:image?)\n\n    submitter.documents.preload(:blob).reject do |attachment|\n      is_more_than_two_images &&\n        original_documents.find { |a| a.uuid == (attachment.metadata['original_uuid'] || attachment.uuid) }&.image?\n    end\n  end\n\n  def create_attachment!(submitter, file, metadata: {})\n    raise ParamsError, 'file param is missing' if file.blank?\n\n    extension = File.extname(file.original_filename).delete_prefix('.').downcase\n\n    if DANGEROUS_EXTENSIONS.include?(extension)\n      raise MaliciousFileExtension, \"File type '.#{extension}' is not allowed.\"\n    end\n\n    blob = ActiveStorage::Blob.create_and_upload!(io: file.tap(&:rewind).open,\n                                                  filename: file.original_filename,\n                                                  content_type: file.content_type,\n                                                  metadata:)\n\n    ActiveStorage::Attachment.create!(blob:, name: 'attachments', record: submitter)\n  end\n\n  def normalize_preferences(account, user, params)\n    preferences = {}\n\n    message_params = params['message'].presence || params.slice('subject', 'body').presence\n\n    if message_params.present?\n      email_message = EmailMessages.find_or_create_for_account_user(account, user,\n                                                                    message_params['subject'],","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/docusealco/docuseal/blob/004a22c1c88109c7ba0b567df011a8cb13894001/lib/submitters.rb#L114-L150","documentation":"Submitters.create_attachment! (lib/submitters.rb:132) raises MaliciousFileExtension when the uploaded file's original filename has an extension in Submitters::DANGEROUS_EXTENSIONS — a blocklist of executables, scripts, installers and libraries (exe, bat, cmd, sh, js, jar, dll, dmg, apk, ...). Only the filename extension is inspected; content is not sniffed at this guard. The error stops the blob from ever being created.","triggerScenarios":"Uploading any file whose name ends in a blocklisted extension to a submitter attachments endpoint (e.g. contract.exe, script.sh, macro-enabled archives like .jar); a legitimate document misnamed with a dangerous extension (report.scr).","commonSituations":"Users attaching 'signed_docs.zip.exe' style malware; internal tooling uploading build artifacts; files renamed by email clients; testers probing the upload endpoint with script files.","solutions":["Upload documents in allowed formats (pdf, png/jpg, docx, xlsx) — rename the file so its extension matches its real content.","For archives or binaries that are legitimately needed, deliver them out-of-band; the endpoint will not accept them.","Rescue Submitters::MaliciousFileExtension in the controller and return 422 with the message so the UI can show which extension was rejected.","Do not try to bypass by double extensions — File.extname takes the last segment, so 'a.pdf.exe' is rejected and 'a.exe.pdf' is judged by 'pdf'."],"exampleFix":"# before\nSubmitters.create_attachment!(submitter, params[:file]) # raises for 'malware.exe'\n\n# after\nbegin\n  Submitters.create_attachment!(submitter, params[:file])\nrescue Submitters::MaliciousFileExtension => e\n  render json: { error: e.message }, status: :unprocessable_entity\nend","handlingStrategy":"validation","validationCode":"# Blocklist check identical to the server's, before uploading\nDANGEROUS = Submitters::DANGEROUS_EXTENSIONS\next = File.extname(file.original_filename.to_s).delete_prefix('.').downcase\nraise ArgumentError, \"File type '.#{ext}' is not allowed.\" if DANGEROUS.include?(ext)","typeGuard":null,"tryCatchPattern":"begin\n  Submitters.create_attachment!(submitter, params[:file])\nrescue Submitters::MaliciousFileExtension => e\n  render json: { error: e.message }, status: :unprocessable_entity\nend","preventionTips":["Restrict the file picker accept attribute to safe document/image types.","Remember only the filename extension is checked here — keep names honest.","File.extname takes the LAST segment: 'a.pdf.exe' is rejected, 'a.exe.pdf' passes the name check.","Return the message verbatim so users see which extension tripped it."],"tags":["docuseal","file-upload","security","extension-blocklist"],"backgroundTag":"blocked-file-extension","analyzedSha":"004a22c1c88109c7ba0b567df011a8cb13894001","analyzedAt":"2026-08-21T13:38:23.343Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}