fix(shell-snapshot): prevent shell injection in restore_script via path escaping#74
Closed
fix(shell-snapshot): prevent shell injection in restore_script via path escaping#74
Conversation
…th escaping The restore_script function was vulnerable to shell injection when paths contained single quotes. An attacker could craft a path like: /tmp/test'; rm -rf /; echo ' which would execute arbitrary commands when the restore script was sourced. Changes: - Add shell_escape_path() helper function that properly escapes paths - Use POSIX-compliant quoting technique for single quotes: '"'"' - Paths without single quotes are simply wrapped in single quotes - Add comprehensive unit tests for path escaping Security Impact: This is a security fix that prevents potential command injection attacks through maliciously crafted snapshot paths. Fixes: issue #5406
Greptile OverviewGreptile SummaryThis PR fixes a shell injection vulnerability in the Key changes:
Issue found:
Confidence Score: 3/5
|
| Filename | Overview |
|---|---|
| src/cortex-shell-snapshot/src/snapshot.rs | Added shell_escape_path() helper to prevent shell injection in restore_script() by escaping paths with single quotes |
Sequence Diagram
sequenceDiagram
participant User
participant ShellSnapshot
participant shell_escape_path
participant Shell
User->>ShellSnapshot: restore_script()
ShellSnapshot->>ShellSnapshot: Get restore header
ShellSnapshot->>shell_escape_path: Escape path with single quotes
alt Path contains single quotes
shell_escape_path->>shell_escape_path: Replace ' with '"'"'
shell_escape_path-->>ShellSnapshot: 'path'"'"'with'"'"'quotes'
else Path is simple
shell_escape_path-->>ShellSnapshot: '/simple/path'
end
ShellSnapshot->>ShellSnapshot: Format script with escaped path
ShellSnapshot-->>User: source {escaped_path}
User->>Shell: Execute restore script
Shell->>Shell: Source snapshot file safely
Comment on lines
+207
to
+220
| fn shell_escape_path(path: &Path) -> String { | ||
| let path_str = path.display().to_string(); | ||
|
|
||
| if !path_str.contains('\'') { | ||
| // Simple case: no single quotes, just wrap in single quotes | ||
| format!("'{}'", path_str) | ||
| } else { | ||
| // Complex case: escape single quotes using '"'"' technique | ||
| // This closes the single-quoted string, adds a double-quoted single quote, | ||
| // and reopens the single-quoted string | ||
| let escaped = path_str.replace('\'', "'\"'\"'"); | ||
| format!("'{}'", escaped) | ||
| } | ||
| } |
There was a problem hiding this comment.
paths with embedded newlines could cause unexpected behavior - source command will terminate at the first newline inside the single-quoted path, potentially leading to command injection
Suggested change
| fn shell_escape_path(path: &Path) -> String { | |
| let path_str = path.display().to_string(); | |
| if !path_str.contains('\'') { | |
| // Simple case: no single quotes, just wrap in single quotes | |
| format!("'{}'", path_str) | |
| } else { | |
| // Complex case: escape single quotes using '"'"' technique | |
| // This closes the single-quoted string, adds a double-quoted single quote, | |
| // and reopens the single-quoted string | |
| let escaped = path_str.replace('\'', "'\"'\"'"); | |
| format!("'{}'", escaped) | |
| } | |
| } | |
| fn shell_escape_path(path: &Path) -> String { | |
| let path_str = path.display().to_string(); | |
| // Check for newlines which could break the command | |
| if path_str.contains('\n') || path_str.contains('\r') { | |
| // For paths with newlines, use $'...' syntax with proper escaping | |
| let escaped = path_str | |
| .replace('\\', r"\\") | |
| .replace('\'', r"\'") | |
| .replace('\n', r"\n") | |
| .replace('\r', r"\r"); | |
| format!("$'{}'", escaped) | |
| } else if !path_str.contains('\'') { | |
| // Simple case: no single quotes, just wrap in single quotes | |
| format!("'{}'", path_str) | |
| } else { | |
| // Complex case: escape single quotes using '"'"' technique | |
| let escaped = path_str.replace('\'', "'\"'\"'"); | |
| format!("'{}'", escaped) | |
| } | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/cortex-shell-snapshot/src/snapshot.rs
Line: 207:220
Comment:
paths with embedded newlines could cause unexpected behavior - `source` command will terminate at the first newline inside the single-quoted path, potentially leading to command injection
```suggestion
fn shell_escape_path(path: &Path) -> String {
let path_str = path.display().to_string();
// Check for newlines which could break the command
if path_str.contains('\n') || path_str.contains('\r') {
// For paths with newlines, use $'...' syntax with proper escaping
let escaped = path_str
.replace('\\', r"\\")
.replace('\'', r"\'")
.replace('\n', r"\n")
.replace('\r', r"\r");
format!("$'{}'", escaped)
} else if !path_str.contains('\'') {
// Simple case: no single quotes, just wrap in single quotes
format!("'{}'", path_str)
} else {
// Complex case: escape single quotes using '"'"' technique
let escaped = path_str.replace('\'', "'\"'\"'");
format!("'{}'", escaped)
}
}
```
How can I resolve this? If you propose a fix, please make it concise.
echobt
added a commit
that referenced
this pull request
Feb 4, 2026
This PR consolidates the following fixes: - #74: Prevent shell injection in restore_script via path escaping - #76: Replace unsafe unwrap() with expect() in init_client - #78: Use secure random temp files in external editor to prevent symlink attacks - #79: Add per-chunk streaming timeout to prevent indefinite hangs Key changes: - Added shell escaping for paths in shell-snapshot restore scripts - Replaced unwrap() with expect() for better error context in exec runner - Use secure random temp files instead of predictable names - Added streaming chunk timeout to prevent hangs during LLM responses
Contributor
Author
|
Consolidated into #82 - fix: consolidated security and robustness improvements |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fix shell injection vulnerability in shell snapshot restore_script function.
Problem
The restore_script function was vulnerable to shell injection when paths contained single quotes.
Solution
Related Issue
Fixes issue #5406