mirror of
https://github.com/docker/docker-agent.git
synced 2026-11-04 10:02:15 +00:00
fix(cache): address race condition, resource leak, and path traversal
- Fix race condition in cache.Store: hold lock during persist to ensure snapshot consistency with disk writes - Fix resource leak in syncDir: use defer to ensure directory fd is closed - Add path traversal validation in teamloader: prevent cache paths from escaping parent directory using filepath.Clean and prefix check - Add test for path traversal protection Assisted-By: docker-agent
This commit is contained in:
1 parent
7b898074c2
commit
2dea44efee
3 files changed
+35
-7
No files matched your search
Vendored
+3
-7
@@ -121,14 +121,10 @@ func (c *cache) Store(question, response string) {
|
||||
key := c.normalize(question)
|
||||
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.entries[key] = response
|
||||
var snapshot map[string]string
|
||||
if c.persist != nil {
|
||||
snapshot = maps.Clone(c.entries)
|
||||
}
|
||||
c.mu.Unlock()
|
||||
|
||||
if c.persist != nil {
|
||||
snapshot := maps.Clone(c.entries)
|
||||
c.persist(snapshot)
|
||||
}
|
||||
}
|
||||
@@ -220,6 +216,6 @@ func syncDir(dir string) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer d.Close()
|
||||
_ = d.Sync()
|
||||
_ = d.Close()
|
||||
}
|
||||
@@ -174,6 +174,12 @@ func LoadWithConfig(ctx context.Context, agentSource config.Source, runConfig *c
|
||||
cachePath := agentConfig.Cache.Path
|
||||
if cachePath != "" && !filepath.IsAbs(cachePath) {
|
||||
cachePath = filepath.Join(parentDir, cachePath)
|
||||
cachePath = filepath.Clean(cachePath)
|
||||
// Ensure the resolved path is within parentDir to prevent path traversal
|
||||
cleanParent := filepath.Clean(parentDir) + string(filepath.Separator)
|
||||
if !strings.HasPrefix(cachePath+string(filepath.Separator), cleanParent) {
|
||||
return nil, fmt.Errorf("agent %q: cache path %q escapes parent directory", agentConfig.Name, agentConfig.Cache.Path)
|
||||
}
|
||||
}
|
||||
c, err := cache.New(cache.Config{
|
||||
Enabled: true,
|
||||
|
||||
@@ -483,3 +483,29 @@ func TestExternalDepthContext(t *testing.T) {
|
||||
ctx = contextWithExternalDepth(ctx, 7)
|
||||
assert.Equal(t, 7, externalDepthFromContext(ctx))
|
||||
}
|
||||
|
||||
func TestLoadWithConfig_CachePathTraversal(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// Create a config file with a path traversal attempt
|
||||
configPath := filepath.Join(tmpDir, "agent.yaml")
|
||||
configContent := `
|
||||
agents:
|
||||
root:
|
||||
model: openai/gpt-4o
|
||||
description: Test agent
|
||||
instruction: You are a test agent.
|
||||
cache:
|
||||
enabled: true
|
||||
path: ../../../../etc/passwd
|
||||
`
|
||||
require.NoError(t, os.WriteFile(configPath, []byte(configContent), 0o600))
|
||||
|
||||
source := config.NewFileSource(configPath)
|
||||
runConfig := &config.RuntimeConfig{}
|
||||
runConfig.WorkingDir = tmpDir
|
||||
|
||||
_, err := LoadWithConfig(t.Context(), source, runConfig)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "escapes parent directory")
|
||||
}
|
||||
Reference in new issue
Block a user