-
Notifications
You must be signed in to change notification settings - Fork 1
π‘οΈ Sentinel: Fix TOCTOU vulnerability in SSH key creation #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| ## 2025-02-14 - Shell Script TOCTOU Vulnerability | ||
|
Check failure on line 1 in .jules/sentinel.md
|
||
| **Vulnerability:** SSH keys were created with default permissions (often world-readable) before being restricted with `chmod`, creating a race condition (TOCTOU). | ||
|
Check failure on line 2 in .jules/sentinel.md
|
||
| **Learning:** Shell scripts using `>` redirection to create sensitive files inherit the current umask, leading to insecure default permissions. | ||
|
Check failure on line 3 in .jules/sentinel.md
|
||
| **Prevention:** Always use `umask 077` in a subshell `(umask 077; command > file)` when creating sensitive files in shell scripts. | ||
|
Check failure on line 4 in .jules/sentinel.md
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| #!/bin/bash | ||
| set -e | ||
|
|
||
| # Setup mock environment | ||
| TEST_DIR="$(mktemp -d)" | ||
| MOCK_BIN="$TEST_DIR/bin" | ||
| mkdir -p "$MOCK_BIN" | ||
| export PATH="$MOCK_BIN:$PATH" | ||
|
|
||
| # Mock 'op' | ||
| cat << 'EOF' > "$MOCK_BIN/op" | ||
| #!/bin/bash | ||
| if [[ "$1" == "item" && "$2" == "get" ]]; then | ||
| # Pretend key exists in 1Password | ||
| exit 0 | ||
| elif [[ "$1" == "read" ]]; then | ||
| echo "dummy-key-content" | ||
| exit 0 | ||
| else | ||
| # Allow other commands (like account list) | ||
| exit 0 | ||
| fi | ||
| EOF | ||
| chmod +x "$MOCK_BIN/op" | ||
|
|
||
| # Mock 'chmod' to inspect permissions | ||
| cat << 'EOF' > "$MOCK_BIN/chmod" | ||
| #!/bin/bash | ||
| target="${@: -1}" | ||
| if [[ -f "$target" ]]; then | ||
| perms=$(ls -l "$target" | awk '{print $1}') | ||
| echo "MOCK CHMOD: Inspecting $target before chmod: $perms" | ||
| fi | ||
| # Do nothing (mocked) or actually change permissions? | ||
| # If we do nothing, the file remains with creation permissions. | ||
| # This helps us verify the umask effect. | ||
| EOF | ||
| chmod +x "$MOCK_BIN/chmod" | ||
|
|
||
| # Set up test environment | ||
| export HOME="$TEST_DIR" | ||
| export XDG_CONFIG_HOME="$TEST_DIR/.config" | ||
| export XDG_DATA_HOME="$TEST_DIR/.local/share" | ||
| export XDG_STATE_HOME="$TEST_DIR/.local/state" | ||
|
|
||
| # Create config file | ||
| mkdir -p "$XDG_CONFIG_HOME/dotfiles" | ||
| echo "ssh: | ||
| vault: development | ||
| item_name: SSH Key | ||
| key_type: ed25519" > "$XDG_CONFIG_HOME/dotfiles/config.yaml" | ||
|
|
||
| # Run the script | ||
| # We expect it to restore the key | ||
| echo "Running tools/setup-ssh-keys.sh restore..." | ||
| # We pipe 'y' to confirm overwrite if prompted (though initial restore shouldn't need it) | ||
| echo "y" | ./tools/setup-ssh-keys.sh restore | ||
|
|
||
| # Verify output | ||
| # The output should contain "MOCK CHMOD: Inspecting ... before chmod: -rw-r--r--" for private key (if vulnerable) | ||
| # or "-rw-------" (if secure) | ||
|
|
||
| # Cleanup | ||
| rm -rf "$TEST_DIR" | ||
|
Comment on lines
+59
to
+64
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test has no assertions β it will always pass regardless of actual permissions. Lines 59β61 describe the expected output in comments but never actually check it. The test exits 0 whether the private key was created with Additionally, with Proposed fix+# Cleanup on exit (including failures)
+cleanup() { rm -rf "$TEST_DIR"; }
+trap cleanup EXIT
+
# Run the script
echo "Running tools/setup-ssh-keys.sh restore..."
-echo "y" | ./tools/setup-ssh-keys.sh restore
+OUTPUT=$(echo "y" | ./tools/setup-ssh-keys.sh restore 2>&1)
-# Verify output
-# The output should contain "MOCK CHMOD: Inspecting ... before chmod: -rw-r--r--" for private key (if vulnerable)
-# or "-rw-------" (if secure)
+# Assert private key was created with secure permissions (umask 077 β -rw-------)
+PRIVATE_KEY="$TEST_DIR/.ssh/id_ed25519"
+if [[ -f "$PRIVATE_KEY" ]]; then
+ PERMS=$(stat -c '%a' "$PRIVATE_KEY" 2>/dev/null || stat -f '%Lp' "$PRIVATE_KEY")
+ if [[ "$PERMS" != "600" ]]; then
+ echo "FAIL: Private key has permissions $PERMS, expected 600"
+ exit 1
+ fi
+ echo "PASS: Private key created with permissions $PERMS"
+else
+ echo "FAIL: Private key file not found"
+ exit 1
+fi
-# Cleanup
-rm -rf "$TEST_DIR"
+echo "All security permission tests passed."Note: π€ Prompt for AI Agents |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix markdown lint failures flagged by CI.
The "Lint Documentation" check is failing with multiple violations:
#) and no blank line after the heading.Also, the date reads 2025-02-14 β likely should be 2026-02-14 given the PR timestamp.
Proposed fix
π Committable suggestion
π§° Tools
πͺ GitHub Check: Lint Documentation
[failure] 4-4: Line length
.jules/sentinel.md:4:81 MD013/line-length Line length [Expected: 80; Actual: 130] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md013.md
[failure] 3-3: Line length
.jules/sentinel.md:3:81 MD013/line-length Line length [Expected: 80; Actual: 143] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md013.md
[failure] 2-2: Line length
.jules/sentinel.md:2:81 MD013/line-length Line length [Expected: 80; Actual: 162] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md013.md
[failure] 1-1: First line in a file should be a top-level heading
.jules/sentinel.md:1 MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "## 2025-02-14 - Shell Script T..."] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md041.md
[failure] 1-1: Headings should be surrounded by blank lines
.jules/sentinel.md:1 MD022/blanks-around-headings Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: "## 2025-02-14 - Shell Script TOCTOU Vulnerability"] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md022.md
π€ Prompt for AI Agents