@@ -528,6 +528,8 @@ struct oaicompat_parser_options {
528528 bool allow_image;
529529 bool allow_audio;
530530 bool enable_thinking = true ;
531+ int32_t local_media_max_size_mb;
532+ std::string allowed_local_media_path;
531533};
532534
533535// used by /chat/completions endpoint
@@ -637,17 +639,31 @@ static json oaicompat_chat_params_parse(
637639 }
638640
639641 } else if (string_starts_with (url, " file://" )) {
640- // Strip off the leading "file://"
641- std::string fname = url.substr (7 );
642- // load local file path
643- raw_buffer buf;
642+ // Strip off the leading "file://"
643+ std::string fname = url.substr (7 );
644+ std::vector<std::string> fparts = string_split<std::string>(fname, std::filesystem::path::preferred_separator);
645+ for (const auto &piece : fparts) {
646+ if (piece != " " && !fs_validate_filename (piece)) {
647+ throw std::runtime_error (" Invalid filename piece '" + piece + " ': " + fname);
648+ }
649+ }
650+ // Check allowed local media path - fs_validate_filename already validated that there is no ".." or "."
651+ if (opt.allowed_local_media_path == " " || !string_starts_with (fname, opt.allowed_local_media_path )) {
652+ throw std::runtime_error (" File path not allowed" );
653+ }
654+ // load local file path
655+ raw_buffer buf;
644656 FILE * f = fopen (fname.c_str (), " rb" );
645657 if (!f) {
646658 LOG_ERR (" Unable to open file %s: %s\n " , fname.c_str (), strerror (errno));
647659 throw std::runtime_error (" Unable to open image file" );
648660 }
649661 fseek (f, 0 , SEEK_END);
650662 long file_size = ftell (f);
663+ if (file_size > opt.local_media_max_size_mb * 1024 * 1024 ) {
664+ fclose (f);
665+ throw std::runtime_error (" Local file exceeds maximum allowed size" );
666+ }
651667 fseek (f, 0 , SEEK_SET);
652668 buf.resize (file_size);
653669 size_t n_read = fread (buf.data (), 1 , file_size, f);
@@ -656,9 +672,9 @@ static json oaicompat_chat_params_parse(
656672 LOG_ERR (" Failed to read entire file %s" , fname.c_str ());
657673 throw std::runtime_error (" Failed to read entire image file" );
658674 }
659- out_files.push_back (buf);
675+ out_files.push_back (buf);
660676
661- } else {
677+ } else {
662678 // try to decode base64 image
663679 std::vector<std::string> parts = string_split<std::string>(url, /* separator*/ ' ,' );
664680 if (parts.size () != 2 ) {
0 commit comments