Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"@tailwindcss/vite": "^4.3.2",
"@tanstack/react-query": "^5.90.12",
"ai": "^6.0.199",
"astro": "^7.0.6",
"astro": "^7.1.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"dompurify": "^3.4.7",
Expand All @@ -42,6 +42,10 @@
"@types/react": "^18.3.28",
"@types/react-dom": "^18.3.7",
"typescript": "~6.0.3"
},
"pnpm": {
"overrides": {
"js-yaml": ">=4.3.0"
}
}
}

375 changes: 189 additions & 186 deletions docs/pnpm-lock.yaml

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ require (
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/procfs v0.20.1 // indirect
github.com/richardlehane/mscfb v1.0.6 // indirect
github.com/richardlehane/mscfb v1.0.7 // indirect
github.com/richardlehane/msoleps v1.0.6 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/robertkrimen/otto v0.5.1 // indirect
Expand Down Expand Up @@ -304,7 +304,7 @@ require (
github.com/xeipuuv/gojsonschema v1.2.0
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/xuri/efp v0.0.1 // indirect
github.com/xuri/excelize/v2 v2.10.1 // indirect
github.com/xuri/excelize/v2 v2.11.0 // indirect
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
github.com/yuin/gopher-lua v1.1.1 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -617,8 +617,8 @@ github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTU
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=
github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=
github.com/richardlehane/mscfb v1.0.6 h1:eN3bvvZCp00bs7Zf52bxNwAx5lJDBK1tCuH19qq5aC8=
github.com/richardlehane/mscfb v1.0.6/go.mod h1:pe0+IUIc0AHh0+teNzBlJCtSyZdFOGgV4ZK9bsoV+Jo=
github.com/richardlehane/mscfb v1.0.7 h1:oeoiM0WE79vHwE8RpIYYvIAc8ajTH2mb6UZm55/+EB0=
github.com/richardlehane/mscfb v1.0.7/go.mod h1:pe0+IUIc0AHh0+teNzBlJCtSyZdFOGgV4ZK9bsoV+Jo=
github.com/richardlehane/msoleps v1.0.6 h1:9BvkpjvD+iUBalUY4esMwv6uBkfOip/Lzvd93jvR9gg=
github.com/richardlehane/msoleps v1.0.6/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
Expand Down Expand Up @@ -739,8 +739,8 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavM
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=
github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.10.1 h1:V62UlqopMqha3kOpnlHy2CcRVw1V8E63jFoWUmMzxN0=
github.com/xuri/excelize/v2 v2.10.1/go.mod h1:iG5tARpgaEeIhTqt3/fgXCGoBRt4hNXgCp3tfXKoOIc=
github.com/xuri/excelize/v2 v2.11.0 h1:HxaEFl6sRN2+8J5a8HaKq+0M4FsjBGMnWWtjOCPSG88=
github.com/xuri/excelize/v2 v2.11.0/go.mod h1:jxFLbzaIwGQ5ufFNvYfUOHqXhfPaNmP14KWfmNz2Uak=
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE=
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
Expand Down
2 changes: 1 addition & 1 deletion pkg/cli/ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import (
"github.com/flanksource/captain/pkg/ai/middleware"
"github.com/flanksource/captain/pkg/ai/pricing"
"github.com/flanksource/captain/pkg/api"
"github.com/flanksource/captain/pkg/collections"
"github.com/flanksource/captain/pkg/captainconfig"
"github.com/flanksource/captain/pkg/claude"
"github.com/flanksource/captain/pkg/claude/tools"
"github.com/flanksource/captain/pkg/collections"
dbcontext "github.com/flanksource/commons-db/context"
"github.com/flanksource/commons-db/shell"
)
Expand Down
6 changes: 6 additions & 0 deletions pkg/cli/permission_catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ func resolveCatalogDir(baseCwd, dir string) (string, error) {
return base, nil
}

// Reject traversal sequences in the raw input before any path is built;
// the prefix check below is defense in depth.
if strings.Contains(dir, "..") {
return "", fmt.Errorf("dir %q contains a path traversal sequence", dir)
}
Comment on lines +49 to +53

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject .. path segments, not arbitrary substrings.

strings.Contains rejects valid directory names such as reports..archive, even though they do not perform traversal. Check normalized path components for an exact .. segment and add a regression test for a legitimate double-dot directory name.

Proposed fix
-	if strings.Contains(dir, "..") {
-		return "", fmt.Errorf("dir %q contains a path traversal sequence", dir)
+	for _, segment := range strings.Split(filepath.ToSlash(dir), "/") {
+		if segment == ".." {
+			return "", fmt.Errorf("dir %q contains a path traversal sequence", dir)
+		}
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Reject traversal sequences in the raw input before any path is built;
// the prefix check below is defense in depth.
if strings.Contains(dir, "..") {
return "", fmt.Errorf("dir %q contains a path traversal sequence", dir)
}
// Reject traversal sequences in the raw input before any path is built;
// the prefix check below is defense in depth.
for _, segment := range strings.Split(filepath.ToSlash(dir), "/") {
if segment == ".." {
return "", fmt.Errorf("dir %q contains a path traversal sequence", dir)
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/cli/permission_catalog.go` around lines 49 - 53, Update the traversal
validation in the directory-handling function to reject only exact ".." path
components after splitting or normalizing the input, rather than any substring
match. Preserve rejection of actual traversal segments while allowing legitimate
names such as "reports..archive", and add a regression test covering that valid
directory name.


target := dir
if !filepath.IsAbs(target) {
target = filepath.Join(base, target)
Expand Down
4 changes: 3 additions & 1 deletion pkg/cli/permission_catalog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,12 @@ func TestResolveCatalogDir(t *testing.T) {
t.Fatalf("relative dir: got %q err %v, want %q", got, err, nested)
}

// Traversal attempts must be rejected.
// Traversal attempts must be rejected, including ".." segments that would
// still resolve inside the workspace.
for _, dir := range []string{
"../../etc",
filepath.Join("sub", "..", "..", "etc"),
"sub/../sub/child",
"/etc",
} {
if got, err := resolveCatalogDir(base, dir); err == nil {
Expand Down
6 changes: 3 additions & 3 deletions pkg/cli/prompt_run_stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,9 @@ func (b *runBroker) prune(maxAge time.Duration) {

type promptRunSnapshotBody struct {
Entries []session.Message `json:"entries"`
Done bool `json:"done"`
Summary *PromptRunSummary `json:"summary,omitempty"`
Error string `json:"error,omitempty"`
Done bool `json:"done"`
Summary *PromptRunSummary `json:"summary,omitempty"`
Error string `json:"error,omitempty"`
}

// handlePromptRunStream streams a run's session.Message frames as SSE:
Expand Down
Loading