Skip to content

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

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

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

Conversation

@adrianlizarraga

@adrianlizarraga adrianlizarraga commented May 21, 2026

Copy link
Copy Markdown
Contributor

Description

Adds path validation for the ep_cache_context attribute in the OpenVINO Execution Provider to prevent path traversal attacks. A malicious ONNX model could craft an ep_cache_context value (e.g., ../../../../etc/passwd) to read arbitrary files from the host filesystem when using embed_mode=0 (external blob file).

This aligns the OpenVINO EP with the existing validation already present in the TensorRT EP and NV TensorRT RTX EP.

Changes

  • Added ValidateEpCacheContextPath() which:
    • Rejects empty ep_cache_context values
    • Rejects absolute paths (Unix / and Windows C:\ style)
    • Resolves symlinks via std::filesystem::weakly_canonical to prevent symlink-based traversal
    • Verifies the resolved cache path is contained within the model directory using component-wise prefix checking
    • Handles symlinked model files (e.g., HuggingFace Hub cache layout) by also checking against the real model directory
  • Validation is applied in both code paths that use ep_cache_context as a file path:
    • GetModelBlobStream() — blob loading during inference
    • Initialize() — shared context initialization

Motivation

Without this validation, a crafted ONNX model with a path-traversing ep_cache_context attribute could cause the OpenVINO EP to open and read arbitrary files accessible to the process. This is a security hardening change to ensure the EP only loads blob files from within the model's own directory tree.

Testing

  • Verified that legitimate models with relative blob paths within the model directory continue to work
  • Verified that absolute paths, ../-based traversal, and symlink escapes are rejected

@adrianlizarraga
adrianlizarraga requested a review from Copilot May 21, 2026 04:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 thread onnxruntime/core/providers/openvino/onnx_ctx_model_helper.cc Outdated
Comment thread onnxruntime/core/providers/openvino/onnx_ctx_model_helper.cc Outdated
Comment thread onnxruntime/core/providers/openvino/onnx_ctx_model_helper.cc Outdated
@adrianlizarraga adrianlizarraga changed the title [OpenVINO EP] Validate that EPContext binary path is within model con… [OpenVINO EP] Validate that EPContext binary path is within model directory May 21, 2026
@yuslepukhin yuslepukhin self-assigned this May 29, 2026
@yuslepukhin

Copy link
Copy Markdown
Contributor

Closing in favor of #28725

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.

3 participants