-
Notifications
You must be signed in to change notification settings - Fork 1
π‘οΈ Sentinel: [CRITICAL] Fix TOCTOU vulnerability in ssh key restore #84
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
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-20 - TOCTOU Vulnerability in SSH Key Restoration | ||
|
Check failure on line 1 in .jules/sentinel.md
|
||
| **Vulnerability:** Time-of-Check to Time-of-Use (TOCTOU) when restoring SSH private keys from 1Password. | ||
|
Check failure on line 2 in .jules/sentinel.md
|
||
| **Learning:** Writing sensitive data to a file using default permissions and then using `chmod 600` leaves the file briefly readable by other users on the system between the write and the chmod. | ||
|
Check failure on line 3 in .jules/sentinel.md
|
||
| **Prevention:** Use a subshell with `umask 077` (e.g., `(umask 077 && command > file)`) to ensure the file is created with secure permissions (600) from the start. | ||
|
Check failure on line 4 in .jules/sentinel.md
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -149,15 +149,15 @@ cmd_restore() { | |
| say "Restoring SSH key from 1Password..." | ||
|
|
||
| # Create SSH directory | ||
| mkdir -p "$SSH_DIR" | ||
| (umask 077 && mkdir -p "$SSH_DIR") | ||
| chmod 700 "$SSH_DIR" | ||
|
|
||
| # Read private key from 1Password and save locally | ||
| op read "op://$VAULT/$KEY_NAME/private_key" > "$PRIVATE_KEY_FILE" | ||
| (umask 077 && op read "op://$VAULT/$KEY_NAME/private_key" > "$PRIVATE_KEY_FILE") | ||
| chmod 600 "$PRIVATE_KEY_FILE" | ||
|
|
||
| # Read public key from 1Password and save locally | ||
| op read "op://$VAULT/$KEY_NAME/public_key" > "$PUBLIC_KEY_FILE" | ||
| (umask 022 && op read "op://$VAULT/$KEY_NAME/public_key" > "$PUBLIC_KEY_FILE") | ||
| chmod 644 "$PUBLIC_KEY_FILE" | ||
|
Comment on lines
+156
to
161
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. π§© Analysis chainπ Script executed: #!/bin/bash
set -euo pipefail
f="$(mktemp)"
printf 'EXISTING_KEY\n' > "$f"
# Simulate a failing command with direct redirection.
(false > "$f") || true
# Expected: file size becomes 0, demonstrating truncation-before-success.
wc -c "$f"Repository: kidchenko/dotfiles Length of output: 83 π Script executed: # First, locate the setup-ssh-keys.sh file
find . -name "setup-ssh-keys.sh" -type fRepository: kidchenko/dotfiles Length of output: 87 π Script executed: # Once found, let's read the relevant section
sed -n '140,175p' tools/setup-ssh-keys.shRepository: kidchenko/dotfiles Length of output: 1085 π Script executed: # Also check for the cmd_restore function definition and context
sed -n '1,160p' tools/setup-ssh-keys.sh | tail -100Repository: kidchenko/dotfiles Length of output: 3333 π Script executed: # Check for variable definitions: SSH_DIR, KEY_TYPE, PRIVATE_KEY_FILE, PUBLIC_KEY_FILE
grep -n "SSH_DIR\|KEY_TYPE\|PRIVATE_KEY_FILE\|PUBLIC_KEY_FILE" tools/setup-ssh-keys.sh | head -30Repository: kidchenko/dotfiles Length of output: 1426 π Script executed: # Check the full structure of the script to understand variable scope
head -60 tools/setup-ssh-keys.shRepository: kidchenko/dotfiles Length of output: 1848 π Script executed: # Look for any existing error handling patterns around file operations
grep -B2 -A2 "mv\|atomic\|tmp" tools/setup-ssh-keys.shRepository: kidchenko/dotfiles Length of output: 44 Add error handling and atomic writes for SSH key restore operations. Lines 156β161 truncate the destination files before Proposed atomic-write fix # Read private key from 1Password and save locally
- (umask 077 && op read "op://$VAULT/$KEY_NAME/private_key" > "$PRIVATE_KEY_FILE")
- chmod 600 "$PRIVATE_KEY_FILE"
+ local tmp_private
+ tmp_private="$(mktemp "$SSH_DIR/.id_${KEY_TYPE}.tmp.XXXXXX")"
+ if (umask 077 && op read "op://$VAULT/$KEY_NAME/private_key" > "$tmp_private"); then
+ mv -f "$tmp_private" "$PRIVATE_KEY_FILE"
+ chmod 600 "$PRIVATE_KEY_FILE"
+ else
+ rm -f "$tmp_private"
+ error "Failed to read private key from 1Password"
+ fi
# Read public key from 1Password and save locally
- (umask 022 && op read "op://$VAULT/$KEY_NAME/public_key" > "$PUBLIC_KEY_FILE")
- chmod 644 "$PUBLIC_KEY_FILE"
+ local tmp_public
+ tmp_public="$(mktemp "$SSH_DIR/.id_${KEY_TYPE}.pub.tmp.XXXXXX")"
+ if (umask 022 && op read "op://$VAULT/$KEY_NAME/public_key" > "$tmp_public"); then
+ mv -f "$tmp_public" "$PUBLIC_KEY_FILE"
+ chmod 644 "$PUBLIC_KEY_FILE"
+ else
+ rm -f "$tmp_public"
+ error "Failed to read public key from 1Password"
+ fiπ€ Prompt for AI Agents |
||
|
|
||
| say "SSH key restored to $SSH_DIR" | ||
|
|
||
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 markdownlint violations to unblock docs checks.
Current lines violate heading-level/spacing and line-length rules (MD041, MD022, MD013). Reflowing this section should resolve the documented CI failures.
π Suggested markdown 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: 163] 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: 194] 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: 104] 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-20 - TOCTOU Vulnera..."] 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-20 - TOCTOU Vulnerability in SSH Key Restoration"] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md022.md
π€ Prompt for AI Agents