Skip to content

Harden trash path boundary checks#230

Merged
runkids merged 1 commit into
runkids:mainfrom
jnhu76:security/harden-trash-path-boundaries
Jun 16, 2026
Merged

Harden trash path boundary checks#230
runkids merged 1 commit into
runkids:mainfrom
jnhu76:security/harden-trash-path-boundaries

Conversation

@jnhu76

@jnhu76 jnhu76 commented Jun 16, 2026

Copy link
Copy Markdown

Fix #229

Summary

This PR hardens path boundary checks in internal/trash.

It addresses a function-level contract weakness found during G703 / CWE-22 path traversal triage: MoveToTrash previously accepted a caller-provided name that could contain traversal segments and influence the computed trash path.

This is treated as defense-in-depth hardening rather than a confirmed external exploit path. Current production callers appear to pass sanitized names, but the trash helpers perform filesystem write/move/delete/restore operations and should enforce their own invariants.

Changes

  • Add validation for trash-relative names.

  • Reject traversal-style names, including:

    • ../outside
    • ../../outside
    • a/../../outside
    • backslash traversal
    • absolute paths
    • NUL-containing names
    • empty / . / ..
  • Preserve safe nested names such as:

    • org/team-skill
    • demo/my-agent
  • Add under-base checks before filesystem operations.

  • Add a stricter cleanup guard so cleanup cannot remove trashBase itself.

  • Add regression tests in internal/trash/trash_security_test.go.

Scope

Modified files:

  • internal/trash/trash.go
  • internal/trash/trash_security_test.go

No unrelated server, install, sync, config, or git behavior is changed.

Security note

This PR does not claim a confirmed externally exploitable vulnerability. The issue was confirmed as a contract weakness: manually constructed malicious parameters could violate the intended path invariant, even though production callers currently appear to pass sanitized values.

The patch makes the invariant explicit inside the trash helpers.

Validation

  • go test ./... passes.
  • go vet ./... passes.
  • All added security regression tests pass.
  • Existing trash behavior remains compatible with safe nested names.

@runkids runkids marked this pull request as ready for review June 16, 2026 14:57
@runkids runkids merged commit 1ad1358 into runkids:main Jun 16, 2026
7 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e6890039ae

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread internal/trash/trash.go
Comment on lines +44 to +45
if strings.Contains(name, `\`) {
return fmt.Errorf("trash name must not contain backslash: %s", name)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Normalize listed trash names before restoring

On Windows, legitimate nested trash entries produced by List use filepath.Join(parentRel, name), so their TrashEntry.Name contains \ (for example org\skill). The TUI/server restore flows pass those listed entries back into Restore/RestoreAgent, and this new check rejects them with “must not contain backslash,” making nested restores fail on Windows even though the entries were created by the trash code itself. Normalize listed names to slash form before validation, or accept the OS separator for entries sourced from List.

Useful? React with 👍 / 👎.

Comment thread internal/trash/trash.go
Comment on lines +58 to +60
}
if !strings.HasPrefix(candidate, base+string(filepath.Separator)) {
return fmt.Errorf("path %q escapes base %q", candidate, base)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Treat children of '.' as under the base

When a valid global config uses source: . or agents_source: ., restoring a flat item now computes destPath as skill-name, while ensureUnderBase cleans the base to . and then requires the child to start with ./. That rejects normal restores as escaping even though skill-name is inside the current-directory source; use filepath.Rel/absolute normalization instead of this string-prefix check for relative bases.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Harden trash path construction against traversal-style names

2 participants