Skip to content

Commit 47557cf

Browse files
ElanHassonclaude
andcommitted
feat: Add configurable directory restriction for file execution
- Add CSX_ALLOWED_PATH environment variable support for directory restriction - When set, only allows script execution from specified directory - Add test for restricted path validation - Update README with security feature documentation This addresses the additional code review feedback about path security. 🤖 Generated with Claude Code Co-Authored-By: Claude <[email protected]>
1 parent 7e4a95b commit 47557cf

File tree

3 files changed

+36
-0
lines changed

3 files changed

+36
-0
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,9 @@ This will:
244244
- 🔐 Console output is captured to prevent interference with MCP stdio protocol
245245
- 🐳 Docker container runs as non-root user for additional security
246246
- 🛡️ Use appropriate sandboxing when running untrusted scripts
247+
- 📁 File access can be restricted via `CSX_ALLOWED_PATH` environment variable
248+
- 🔒 Only .csx files are allowed for execution
249+
- ⏱️ Scripts have a configurable timeout (default 30 seconds)
247250

248251
## Contributing
249252

src/InfinityFlow.CSharp.Eval/Tools/CSharpEvalTools.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ public async Task<string> EvalCSharp(
4545
return $"Error: Only .csx files are allowed. Provided: {csxFile}";
4646
}
4747

48+
// Optional: Restrict to specific directories for additional security
49+
// This can be configured via environment variable
50+
var allowedPath = Environment.GetEnvironmentVariable("CSX_ALLOWED_PATH");
51+
if (!string.IsNullOrEmpty(allowedPath))
52+
{
53+
var normalizedAllowedPath = Path.GetFullPath(allowedPath);
54+
if (!fullPath.StartsWith(normalizedAllowedPath, StringComparison.OrdinalIgnoreCase))
55+
{
56+
return $"Error: File access is restricted to {normalizedAllowedPath}";
57+
}
58+
}
59+
4860
if (!File.Exists(fullPath))
4961
{
5062
return $"Error: File not found: {fullPath}";

tests/InfinityFlow.CSharp.Eval.Tests/CSharpEvalToolsTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,27 @@ public async Task EvalCSharp_WithNonCsxFile_ReturnsError()
161161
result.Should().Be($"Error: Only .csx files are allowed. Provided: {nonCsxFile}");
162162
}
163163

164+
[Test]
165+
public async Task EvalCSharp_WithRestrictedPath_ReturnsError()
166+
{
167+
// Arrange
168+
var restrictedFile = "/etc/passwd.csx";
169+
Environment.SetEnvironmentVariable("CSX_ALLOWED_PATH", "/tmp");
170+
171+
try
172+
{
173+
// Act
174+
var result = await _sut.EvalCSharp(csxFile: restrictedFile);
175+
176+
// Assert
177+
result.Should().StartWith("Error: File access is restricted to");
178+
}
179+
finally
180+
{
181+
Environment.SetEnvironmentVariable("CSX_ALLOWED_PATH", null);
182+
}
183+
}
184+
164185
[Test]
165186
[Ignore("Timeout functionality needs refinement - infinite loops may not respect cancellation")]
166187
public async Task EvalCSharp_WithTimeout_ReturnsTimeoutError()

0 commit comments

Comments
 (0)