Skip to content

Fix allowed_local_media_path psirt#4199

Open
michalkulakowski wants to merge 5 commits into
mainfrom
mkulakow/allowed_local_media_path_fix
Open

Fix allowed_local_media_path psirt#4199
michalkulakowski wants to merge 5 commits into
mainfrom
mkulakow/allowed_local_media_path_fix

Conversation

@michalkulakowski
Copy link
Copy Markdown
Collaborator

🛠 Summary

JIRA/Issue if applicable.
Describe the changes.

🧪 Checklist

  • Unit tests added.
  • The documentation updated.
  • Change follows security best practices.
    ``

Copilot AI review requested due to automatic review settings May 11, 2026 11:03
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

This PR hardens allowed_local_media_path validation for OpenAI image inputs to prevent prefix-based bypasses (e.g., /allowed_path_private/... being treated as within /allowed_path), and adds a regression test for the bypass case.

Changes:

  • Add a new unit test covering a prefix/sibling-path bypass attempt for local filesystem image URLs.
  • Normalize allowed_local_media_path before doing the prefix comparison in loadImage() to ensure directory-boundary enforcement.

Reviewed changes

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

File Description
src/test/http_openai_handler_test.cpp Adds a regression test ensuring sibling-prefix paths are rejected.
src/llm/apis/openai_api_handler.cpp Introduces path normalization for allowed_local_media_path prior to prefix checking.

Comment thread src/llm/apis/openai_api_handler.cpp Outdated
Comment on lines +51 to +59
std::string normalizeAllowedLocalMediaPath(const std::string& allowedLocalMediaPath) {
if (allowedLocalMediaPath.empty()) {
return allowedLocalMediaPath;
}
const char lastCharacter = allowedLocalMediaPath.back();
if (lastCharacter == '/' || lastCharacter == '\\') {
return allowedLocalMediaPath;
}
return allowedLocalMediaPath + FileSystem::getOsSeparator();
Comment on lines +252 to 255
const auto normalizedAllowedLocalMediaPath = normalizeAllowedLocalMediaPath(allowedLocalMediaPath.value());
const auto firstMissmatch = std::mismatch(imageSource.begin(), imageSource.end(), normalizedAllowedLocalMediaPath.begin(), normalizedAllowedLocalMediaPath.end());
if (firstMissmatch.second != normalizedAllowedLocalMediaPath.end()) {
return absl::InvalidArgumentError("Given filepath is not subpath of allowed_local_media_path");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Good point.

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 2 out of 2 changed files in this pull request and generated 3 comments.

Comment on lines +51 to +66
std::string normalizePathSeparators(const std::string& path) {
std::string normalizedPath = path;
std::replace(normalizedPath.begin(), normalizedPath.end(), '\\', '/');
return normalizedPath;
}

std::string normalizeAllowedLocalMediaPath(const std::string& allowedLocalMediaPath) {
std::string normalizedAllowedLocalMediaPath = normalizePathSeparators(allowedLocalMediaPath);
if (normalizedAllowedLocalMediaPath.empty()) {
return normalizedAllowedLocalMediaPath;
}
if (normalizedAllowedLocalMediaPath.back() == '/') {
return normalizedAllowedLocalMediaPath;
}
return normalizedAllowedLocalMediaPath + '/';
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Good point.

Comment on lines +258 to 263
const auto normalizedAllowedLocalMediaPath = normalizeAllowedLocalMediaPath(allowedLocalMediaPath.value());
const auto normalizedImageSource = normalizePathSeparators(imageSource);
const auto firstMismatch = std::mismatch(normalizedImageSource.begin(), normalizedImageSource.end(), normalizedAllowedLocalMediaPath.begin(), normalizedAllowedLocalMediaPath.end());
if (firstMismatch.second != normalizedAllowedLocalMediaPath.end()) {
return absl::InvalidArgumentError("Given filepath is not subpath of allowed_local_media_path");
}
Comment thread src/llm/apis/openai_api_handler.cpp Outdated
Comment on lines 260 to 263
const auto firstMismatch = std::mismatch(normalizedImageSource.begin(), normalizedImageSource.end(), normalizedAllowedLocalMediaPath.begin(), normalizedAllowedLocalMediaPath.end());
if (firstMismatch.second != normalizedAllowedLocalMediaPath.end()) {
return absl::InvalidArgumentError("Given filepath is not subpath of allowed_local_media_path");
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can we add ut for that?

Michal Kulakowski added 2 commits May 12, 2026 16:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants