🛡️ Sentinel: HIGH Fix path traversal bypass in Lua Sandbox#178
Conversation
Updated the `ResolveSafe` path validation in `GregIoLuaModule.cs` to explicitly ensure base directories end with a trailing slash before using `StartsWith` boundary checks. This prevents directory traversal bypasses where a target path matches the prefix of the base directory (e.g., escaping `/mods/modA` to access `/mods/modA_secret`).
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 0 |
| Duplication | 0 |
AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.
TIP This summary will be updated as you push new changes.
There was a problem hiding this comment.
Pull Request Overview
This PR implements a critical fix for a high-severity path traversal vulnerability within the Lua sandbox by enforcing trailing separator checks during directory validation. Although the repository is currently 'up to standards' according to Codacy, the file GregIoLuaModule.cs is flagged for increased complexity without accompanying test coverage.
The most significant risk is the absence of automated verification for the new validation logic. While the intent of the fix is correct, the complexity of path resolution makes it prone to regressions. The review also identifies inconsistencies in directory handling for append operations and potential issues with relative path resolution if the working directory changes.
About this PR
- Despite the high-severity nature of the path traversal bypass being fixed, no automated unit or integration tests were included in this PR. Relying on manual verification for security-critical sandbox logic increases the risk of future regressions.
Test suggestions
- Verify that a path with a shared prefix but no directory separator (e.g., 'modA_secret' when the sandbox is 'modA') is rejected.
- Verify that the exact sandbox root directory path is allowed.
- Verify that a file nested inside the sandbox root directory is allowed.
- Verify that path traversal attempts using '../' are correctly resolved and blocked if they escape the sandbox root.
Prompt proposal for missing tests
Consider implementing these tests if applicable:
1. Verify that a path with a shared prefix but no directory separator (e.g., 'modA_secret' when the sandbox is 'modA') is rejected.
2. Verify that the exact sandbox root directory path is allowed.
3. Verify that a file nested inside the sandbox root directory is allowed.
4. Verify that path traversal attempts using '../' are correctly resolved and blocked if they escape the sandbox root.
TIP Improve review quality by adding custom instructions
TIP How was this review? Give us feedback
|
|
||
| string dataDirWithSlash = dataDirFull.EndsWith(Path.DirectorySeparatorChar.ToString()) ? dataDirFull : dataDirFull + Path.DirectorySeparatorChar; |
There was a problem hiding this comment.
🔴 HIGH RISK
Suggestion: The validation logic in ResolveSafe is critical for preventing sandbox escapes but currently lacks test coverage and contains high complexity. Additionally, the boundary paths (dataDirFull and dataDirWithSlash) are recalculated on every call. It is recommended to refactor GregIoLuaModule.Register to pre-calculate these boundaries and implement a unit test suite (e.g., using NUnit) to verify that path traversal (../) and prefix-matching bypasses (e.g., /mods/modA_secret vs /mods/modA) are correctly handled.
| try | ||
| { | ||
| var files = Directory.GetFiles(dataDir, pattern ?? "*.*", SearchOption.AllDirectories) | ||
| .Select(f => Path.GetRelativePath(dataDir, f).Replace('\\', '/')) |
There was a problem hiding this comment.
🟡 MEDIUM RISK
Suggestion: Try running the following prompt in your coding agent:
Update the
list_filesimplementation inGregIoLuaModule.csto use the absolute path of the data directory (viaPath.GetFullPath) for bothDirectory.GetFilesandPath.GetRelativePathto ensure it remains robust against changes in the current working directory.
| ioTable["append_file"] = (Action<string, string>)((path, content) => | ||
| { | ||
| try | ||
| { | ||
| string fullPath = ResolveSafe(dataDir, path); | ||
| File.AppendAllText(fullPath, content); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| MelonLogger.Error($"[LuaMod:{modId}] io.append_file('{path}') failed: {ex.Message}"); | ||
| } | ||
| }); | ||
|
|
There was a problem hiding this comment.
⚪ LOW RISK
Suggestion: Try running the following prompt in your coding agent:
In
GregIoLuaModule.cs, update theappend_fileimplementation to ensure the parent directory exists before writing, using the same logic found in thewrite_fileimplementation.
🚨 Severity: HIGH
💡 Vulnerability: Sandbox boundary checking used simple
String.StartsWithon directory paths, which allowed prefix-matching bypasses. For example, a malicious path ending up as/mods/modA_secretwould incorrectly pass the boundary check for/mods/modA.🎯 Impact: A malicious Lua mod could escape its data directory and read/write files in sibling directories with similar prefixes, potentially leading to unauthorized data access or modification.
🔧 Fix: Updated the boundary check to require an exact match to the base directory or enforce that the path starts with the base directory plus a trailing directory separator.
✅ Verification: Tests were run and path traversal logic has been manually reviewed to prevent the prefix-match bypass.
PR created automatically by Jules for task 17803667132840490775 started by @mleem97