Skip to content

[OpenVINO EP] Validate that EPContext binary path is within model con…#28605

Draft
adrianlizarraga wants to merge 5 commits into
mainfrom
adrianl/OVEp_CtxModel_PathTraversal
Draft

[OpenVINO EP] Validate that EPContext binary path is within model con…#28605
adrianlizarraga wants to merge 5 commits into
mainfrom
adrianl/OVEp_CtxModel_PathTraversal

Conversation

@adrianlizarraga
Copy link
Copy Markdown
Contributor

…text directory

Description

Motivation and Context

@adrianlizarraga adrianlizarraga requested a review from Copilot May 21, 2026 04:41
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds validation for the OpenVINO EPContext external-blob path (ep_cache_context) to reduce path traversal risk when loading EPContext artifacts.

Changes:

  • Introduces filesystem-based helpers to classify ep_cache_context as absolute vs. relative.
  • Adds ORT_ENFORCE guards to reject absolute paths and paths containing .. before resolving blob/context file locations.
  • Applies these validations in both EPContext blob reading (GetModelBlobStream) and shared context initialization (Initialize).
Comments suppressed due to low confidence (2)

onnxruntime/core/providers/openvino/onnx_ctx_model_helper.cc:142

  • These checks ensure ep_cache_context is not absolute and doesn't contain "..", but they still allow directory escape if the combined path resolves via symlinks, and they don't guard the case where blob_filepath (base model/context path) is empty (then the lookup becomes relative to the process CWD). Consider computing a canonical/weakly_canonical combined path and enforcing it is within the canonical base directory, and ORT_ENFORCE that the base path is non-empty before joining.
    // ep_cache_context must be a relative path within the context model directory.
    ORT_ENFORCE(!IsAbsolutePath(ep_cache_context),
                "ep_cache_context must be a relative path, but got absolute path: ", ep_cache_context);
    ORT_ENFORCE(!IsRelativePathToParentPath(ep_cache_context),
                "ep_cache_context must not contain '..'; it cannot point outside the model directory.");
    blob_filepath = blob_filepath.parent_path() / ep_cache_context;
    ORT_ENFORCE(std::filesystem::exists(blob_filepath), "Blob file not found: ", blob_filepath.string());

onnxruntime/core/providers/openvino/onnx_ctx_model_helper.cc:275

  • Same path validation issue as in GetModelBlobStream: rejecting absolute paths and ".." is not sufficient to guarantee the resolved ep_context_path stays within the model directory (symlink escape, and GetOutputModelPath() can be empty so the base directory becomes empty). Consider enforcing a non-empty base path and verifying the canonicalized resolved path has the base directory as its prefix.
      // ep_cache_context must be a relative path within the context model directory.
      ORT_ENFORCE(!IsAbsolutePath(ep_cache_context),
                  "ep_cache_context must be a relative path, but got absolute path: ", ep_cache_context);
      ORT_ENFORCE(!IsRelativePathToParentPath(ep_cache_context),
                  "ep_cache_context must not contain '..'; it cannot point outside the model directory.");
      std::filesystem::path ep_context_path = session_context.GetOutputModelPath().parent_path() / ep_cache_context;
      if (ep_context_path.extension() != ".xml") {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread onnxruntime/core/providers/openvino/onnx_ctx_model_helper.cc Outdated
Comment thread onnxruntime/core/providers/openvino/onnx_ctx_model_helper.cc Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

onnxruntime/core/providers/openvino/onnx_ctx_model_helper.cc:145

  • Before calling IsModelStreamXML, please validate that ep_cache_context is non-empty and that the resolved path is a regular file and readable. std::filesystem::exists() returns true for directories too, and std::ifstream can fail to open (permissions, directory path), which currently results in a less actionable failure inside IsModelStreamXML (tellg/seekg/size checks).
    ORT_ENFORCE(!IsRelativePathToParentPath(ep_cache_context),
                "ep_cache_context must not contain '..'; it cannot point outside the model directory.");
    blob_filepath = blob_filepath.parent_path() / ep_cache_context;
    ORT_ENFORCE(std::filesystem::exists(blob_filepath), "Blob file not found: ", blob_filepath.string());
    result.reset((std::istream*)new std::ifstream(blob_filepath, std::ios_base::binary | std::ios_base::in));
  }

Comment on lines 137 to 143
// ep_cache_context must be a relative path within the context model directory.
ORT_ENFORCE(!IsAbsolutePath(ep_cache_context),
"ep_cache_context must be a relative path, but got absolute path: ", ep_cache_context);
ORT_ENFORCE(!IsRelativePathToParentPath(ep_cache_context),
"ep_cache_context must not contain '..'; it cannot point outside the model directory.");
blob_filepath = blob_filepath.parent_path() / ep_cache_context;
ORT_ENFORCE(std::filesystem::exists(blob_filepath), "Blob file not found: ", blob_filepath.string());
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using weakly_canonical

Comment on lines 270 to 276
// ep_cache_context must be a relative path within the context model directory.
ORT_ENFORCE(!IsAbsolutePath(ep_cache_context),
"ep_cache_context must be a relative path, but got absolute path: ", ep_cache_context);
ORT_ENFORCE(!IsRelativePathToParentPath(ep_cache_context),
"ep_cache_context must not contain '..'; it cannot point outside the model directory.");
std::filesystem::path ep_context_path = session_context.GetOutputModelPath().parent_path() / ep_cache_context;
if (ep_context_path.extension() != ".xml") {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now using weakly_canonical

Comment on lines +23 to +31
bool IsRelativePathToParentPath(const std::string& path_string) {
auto normalized = std::filesystem::path(path_string).lexically_normal();
for (const auto& component : normalized) {
if (component == "..") {
return true;
}
}
return false;
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now using weakly_canonical

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants