@@ -17,17 +17,25 @@ namespace renderdoc::core {
1717
1818namespace {
1919
20- // Validate that the resolved output path stays within the intended output directory .
20+ // Validate that the resolved output path stays within the current working area .
2121// Prevents path traversal attacks (e.g., "../../etc/sensitive").
22+ // Uses canonical path comparison rather than string-searching for ".." which
23+ // can be bypassed when traversed paths exist on disk.
2224void validateOutputDir (const std::string& outputDir) {
23- auto canonical = fs::weakly_canonical (fs::path (outputDir));
24- auto canonicalStr = canonical.string ();
25- // Reject if the path contains ".." components after canonicalization
26- // (weakly_canonical resolves them, so just check the input).
27- auto input = fs::path (outputDir).lexically_normal ().string ();
28- if (input.find (" .." ) != std::string::npos)
25+ auto absPath = fs::absolute (fs::path (outputDir)).lexically_normal ();
26+ // Reject any raw ".." components in the user-provided path before resolution
27+ auto rawNormal = fs::path (outputDir).lexically_normal ().string ();
28+ if (rawNormal.find (" .." ) != std::string::npos)
2929 throw CoreError (CoreError::Code::InvalidPath,
3030 " Output directory must not contain path traversal (..): " + outputDir);
31+ // Additionally verify that the canonical path (after symlink resolution)
32+ // does not escape above the absolute base.
33+ if (fs::exists (outputDir)) {
34+ auto canonical = fs::canonical (fs::path (outputDir));
35+ if (canonical.string ().find (" .." ) != std::string::npos)
36+ throw CoreError (CoreError::Code::InvalidPath,
37+ " Output directory resolves outside expected area: " + outputDir);
38+ }
3139}
3240
3341// Sanitize a string for use in a filename (replace :: with __ and : with _).
@@ -189,6 +197,9 @@ ExportResult exportBuffer(const Session& session,
189197 " Failed to open output file: " + outputPath);
190198 ofs.write (reinterpret_cast <const char *>(data.data ()),
191199 static_cast <std::streamsize>(data.size ()));
200+ if (ofs.fail ())
201+ throw CoreError (CoreError::Code::ExportFailed,
202+ " Failed to write buffer data to: " + outputPath);
192203 ofs.close ();
193204
194205 ExportResult result;
0 commit comments