Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 4 additions & 1 deletion config/tmuxinator/default.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{ ... }:
{
xdg.configFile."tmuxinator".source = ./tmuxinator;
xdg.configFile."tmuxinator/primary.yml".source = ./primary.yml;
xdg.configFile."tmuxinator/mobile.yml".source = ./mobile.yml;
xdg.configFile."tmuxinator/work.yml".source = ./work.yml;
xdg.configFile."tmuxinator/desktop.yml".source = ./desktop.yml;
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
71 changes: 17 additions & 54 deletions home-manager/programs/fish/functions/_tsh_function.fish
Original file line number Diff line number Diff line change
@@ -1,72 +1,35 @@
function _tsh_function --description "Search tmux session history log or pane contents"
set -l log ~/.local/share/tmux/session-history.log
function _tsh_function --description "Search tmux pane contents (live + archived)"
set -l pane_dir ~/.local/share/tmux/panes
set -l archive_dir ~/.local/share/tmux/archive

# With argument(s): search stored pane content files (live + archived)
if test (count $argv) -gt 0
if not test -d "$pane_dir"
echo "No pane content store found at $pane_dir"
return
end

set -l query (string join ' ' $argv)
set -l selected (rg -l -- "$query" "$pane_dir" "$archive_dir" 2>/dev/null \
| fzf --prompt="pane-search> " \
--height=40% \
--preview="rg -n -- '$query' {} 2>/dev/null | head -80" \
--preview-window=right:60%)

if test -z "$selected"
return
end

# work--0--0.txt or work--0--0--20260226-103000.txt → sess=work, widx=0
set -l fname (string replace -r '.*/' '' "$selected" \
| string replace -r '--\d{8}-\d{6}\.txt$' '' \
| string replace '.txt' '')
set -l parts (string split -- '--' $fname)
set -l sess $parts[1]
set -l widx $parts[2]

if not tmux has-session -t "$sess" 2>/dev/null
echo "Session '$sess' no longer exists (archived pane — content shown above in preview)"
return
end

if test -n "$TMUX"
tmux switch-client -t "$sess"
tmux select-window -t "$sess:$widx" 2>/dev/null
else
tmux attach-session -t "$sess" \; select-window -t "$sess:$widx"
end
return
end

# No argument: fzf over the history log (session/window/path metadata)
if not test -f "$log"
echo "No session history found at $log"
# Default: fzf over pane content files, optional query pre-fills search
if not test -d "$pane_dir"
echo "No pane content store found at $pane_dir"
return
Comment on lines +6 to 8

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Archive-only search is currently unreachable.

Line [6] returns when pane_dir is missing, even if archive_dir exists. That breaks the intended “live + archived” behavior.

Proposed fix
-  if not test -d "$pane_dir"
-    echo "No pane content store found at $pane_dir"
-    return
-  end
+  set -l search_dirs
+  if test -d "$pane_dir"
+    set -a search_dirs "$pane_dir"
+  end
+  if test -d "$archive_dir"
+    set -a search_dirs "$archive_dir"
+  end
+  if test (count $search_dirs) -eq 0
+    echo "No pane content store found at $pane_dir or $archive_dir"
+    return
+  end
@@
-  set -l selected (rg -l -- "$query" "$pane_dir" "$archive_dir" 2>/dev/null \
+  set -l selected (rg -l -- "$query" $search_dirs 2>/dev/null \

Also applies to: 12-13

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@home-manager/programs/fish/functions/_tsh_function.fish` around lines 6 - 8,
The current early return in _tsh_function.fish aborts when pane_dir is missing
even if archive_dir exists; change the logic so it only returns when neither
pane_dir nor archive_dir exist: update the check around the "if not test -d
\"$pane_dir\"" block (and the similar block around lines 12-13) to test both
pane_dir and archive_dir, proceeding when archive_dir exists (so archive-only
search is reachable) and only echoing "No pane content store..." and returning
when both are absent.

end

set -l selected (cat "$log" | fzf \
--prompt="session-history> " \
--height=40% \
--tac \
--no-sort \
--preview='echo {}')
set -l query (string join ' ' $argv)
set -l selected (rg -l -- "$query" "$pane_dir" "$archive_dir" 2>/dev/null \
| fzf --prompt="pane-search> " \
--height=40% \
--query="$query" \
--preview="rg -n -- '$query' {} 2>/dev/null | head -80" \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-high high

The query variable, derived from user-supplied arguments, is directly interpolated into the fzf --preview command string. Since fzf executes this command in a shell, an attacker can provide a query containing single quotes and shell metacharacters to execute arbitrary commands. For example, a query like foo' ; touch /tmp/pwned ; ' would result in the execution of touch /tmp/pwned.

--preview-window=right:60%)
Comment on lines +11 to +17

@cubic-dev-ai cubic-dev-ai Bot Feb 26, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: This preview command is vulnerable to command injection. If $query contains a single quote (e.g., user's), it breaks the quoting in the shell command executed by fzf, potentially executing arbitrary code.

Escape single quotes in the query before passing it to the preview command.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At home-manager/programs/fish/functions/_tsh_function.fish, line 11:

<comment>This preview command is vulnerable to command injection. If `$query` contains a single quote (e.g., `user's`), it breaks the quoting in the shell command executed by `fzf`, potentially executing arbitrary code. 

Escape single quotes in the query before passing it to the preview command.</comment>

<file context>
@@ -1,72 +1,35 @@
-    --tac \
-    --no-sort \
-    --preview='echo {}')
+  set -l query (string join ' ' $argv)
+  set -l selected (rg -l -- "$query" "$pane_dir" "$archive_dir" 2>/dev/null \
+    | fzf --prompt="pane-search> " \
</file context>
Suggested change
set -l query (string join ' ' $argv)
set -l selected (rg -l -- "$query" "$pane_dir" "$archive_dir" 2>/dev/null \
| fzf --prompt="pane-search> " \
--height=40% \
--query="$query" \
--preview="rg -n -- '$query' {} 2>/dev/null | head -80" \
--preview-window=right:60%)
set -l query (string join ' ' $argv)
set -l query_escaped (string replace -a "'" "'\\''" "$query")
set -l selected (rg -l -- "$query" "$pane_dir" "$archive_dir" 2>/dev/null \
| fzf --prompt="pane-search> " \
--height=40% \
--query="$query" \
--preview="rg -n -- '$query_escaped' {} 2>/dev/null | head -80" \
--preview-window=right:60%)
Fix with Cubic


if test -z "$selected"
return
end

set -l target (string split ' ' $selected)[2]
set -l parts (string split ':' $target)
# work--0--0.txt or work--0--0--20260226-103000.txt → sess=work, widx=0
set -l fname (string replace -r '.*/' '' "$selected" \
| string replace -r '--\d{8}-\d{6}\.txt$' '' \
| string replace '.txt' '')
set -l parts (string split -- '--' $fname)
set -l sess $parts[1]
set -l widx $parts[2]

if not tmux has-session -t "$sess" 2>/dev/null
echo "Session '$sess' no longer exists"
echo "Session '$sess' no longer exists (archived pane — content shown above in preview)"
return
end

Expand Down
39 changes: 39 additions & 0 deletions home-manager/programs/fish/functions/_tss_function.fish
Original file line number Diff line number Diff line change
@@ -1,4 +1,43 @@
function _tss_function --description "Fuzzy-pick or create a tmux session"
set -l log ~/.local/share/tmux/session-history.log

# --log: browse session/window metadata log
if test (count $argv) -gt 0 -a "$argv[1]" = --log
if not test -f "$log"
echo "No session history found at $log"
return
end

set -l selected (cat "$log" | fzf \
--prompt="session-history> " \
--height=40% \
--tac \
--no-sort \
--preview='echo {}')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-high high

The fzf preview command echo {} uses the {} placeholder, which is replaced by the literal content of the selected line from the session history log. Since the log contains session names, window names, and paths that can be influenced by users or processes (e.g., by creating a tmux session with a malicious name), an attacker can inject shell commands into these fields to achieve command execution when the log is browsed via tss --log. For example, a session named $(touch /tmp/pwned) would cause the command to execute when highlighted in the fzf list.


if test -z "$selected"
return
end

set -l target (string split ' ' $selected)[2]
set -l parts (string split ':' $target)
set -l sess $parts[1]
set -l widx $parts[2]
Comment on lines +22 to +25

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "_tss_function.fish" | head -5

Repository: shunkakinoki/dotfiles

Length of output: 122


🏁 Script executed:

cat -n ./home-manager/programs/fish/functions/_tss_function.fish

Repository: shunkakinoki/dotfiles

Length of output: 3250


🏁 Script executed:

find . -name "*session-history*" -o -name "*tss*" | grep -E "(log|script|config)" | head -20

Repository: shunkakinoki/dotfiles

Length of output: 47


🏁 Script executed:

rg "session-history" --type fish --type sh --type bash

Repository: shunkakinoki/dotfiles

Length of output: 93


🏁 Script executed:

rg "session-history"

Repository: shunkakinoki/dotfiles

Length of output: 355


🏁 Script executed:

cat -n ./home-manager/programs/tmux/session-logger.sh

Repository: shunkakinoki/dotfiles

Length of output: 1809


Harden log-entry parsing before using tmux targets.

Line 22 assumes a strict " " (two-space) delimiter and fixed field position [2]; if the log format is malformed or incomplete, $sess and $widx can be empty or invalid. This causes silent failures in the subsequent tmux commands (lines 27, 34, 36) because errors are suppressed. Parse the session:window token defensively and validate before use.

Proposed fix
-    set -l target (string split '  ' $selected)[2]
-    set -l parts (string split ':' $target)
-    set -l sess $parts[1]
-    set -l widx $parts[2]
+    set -l target (string match -r '[^[:space:]]+:[0-9]+' -- $selected)
+    if test -z "$target"
+      echo "Could not parse session/window from: $selected"
+      return 1
+    end
+    set -l parts (string split ':' -- $target)
+    set -l sess $parts[1]
+    set -l widx $parts[2]
📝 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
set -l target (string split ' ' $selected)[2]
set -l parts (string split ':' $target)
set -l sess $parts[1]
set -l widx $parts[2]
set -l target (string match -r '[^[:space:]]+:[0-9]+' -- $selected)
if test -z "$target"
echo "Could not parse session/window from: $selected"
return 1
end
set -l parts (string split ':' -- $target)
set -l sess $parts[1]
set -l widx $parts[2]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@home-manager/programs/fish/functions/_tss_function.fish` around lines 22 -
25, The parsing of the tmux target token is fragile: replace the rigid
split-by-"  " + index access (variables target, parts, sess, widx) with
defensive parsing and validation; first ensure $selected contains a token with a
session:window form, split the token on ':' into parts and check that parts has
at least 2 elements before assigning sess and widx, and if validation fails log
an error or return early instead of calling tmux commands (so the tmux calls
that use sess/widx are not run with empty values); update the code paths that
reference target, parts, sess, and widx to use the validated values only.

Comment on lines +22 to +25

@cubic-dev-ai cubic-dev-ai Bot Feb 26, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Validate the parsed log entry before using it to build tmux targets; otherwise malformed lines can lead to empty session/window values and broken tmux commands.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At home-manager/programs/fish/functions/_tss_function.fish, line 22:

<comment>Validate the parsed log entry before using it to build tmux targets; otherwise malformed lines can lead to empty session/window values and broken tmux commands.</comment>

<file context>
@@ -1,4 +1,43 @@
+      return
+    end
+
+    set -l target (string split '  ' $selected)[2]
+    set -l parts (string split ':' $target)
+    set -l sess $parts[1]
</file context>
Suggested change
set -l target (string split ' ' $selected)[2]
set -l parts (string split ':' $target)
set -l sess $parts[1]
set -l widx $parts[2]
set -l target (string split ' ' $selected)[2]
set -l parts (string split ':' $target)
if test -z "$target" -o (count $parts) -lt 2
echo "Malformed log entry: $selected"
return
end
set -l sess $parts[1]
set -l widx $parts[2]
Fix with Cubic


if not tmux has-session -t "$sess" 2>/dev/null
echo "Session '$sess' no longer exists"
return
end

if test -n "$TMUX"
tmux switch-client -t "$sess"
tmux select-window -t "$sess:$widx" 2>/dev/null
else
tmux attach-session -t "$sess" \; select-window -t "$sess:$widx"
end
return
end

set -l default_sessions primary mobile desktop work

# Build candidate list: default sessions first, then any extra existing sessions
Expand Down
Loading