-
Notifications
You must be signed in to change notification settings - Fork 1
🛡️ Sentinel: [CRITICAL] Fix insecure SSH key creation permissions #28
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 @@ | ||
| ## 2024-02-12 - Insecure SSH Key Creation (TOCTOU) | ||
|
Check failure on line 1 in .jules/sentinel.md
|
||
| **Vulnerability:** `tools/setup-ssh-keys.sh` created sensitive SSH private keys with default permissions (usually 664/644) before restricting them with `chmod 600`. This created a race condition (TOCTOU) where the key was briefly readable by other users. | ||
|
Check failure on line 2 in .jules/sentinel.md
|
||
| **Learning:** Standard shell redirection (`> file`) uses the default umask (typically 022 or 002), resulting in world-readable files for a split second. Relying on a subsequent `chmod` is insecure for sensitive data. | ||
|
Check failure on line 3 in .jules/sentinel.md
|
||
| **Prevention:** Always wrap sensitive file creation commands in a subshell with `umask 077` (e.g., `(umask 077; cmd > file)`). This ensures the file is created with 600 permissions atomically. | ||
|
Check failure on line 4 in .jules/sentinel.md
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,62 @@ | ||||||||||||||||
| #!/bin/bash | ||||||||||||||||
| set -e | ||||||||||||||||
|
|
||||||||||||||||
| # Setup mock environment | ||||||||||||||||
| TEST_DIR="$PWD/tests/tmp" | ||||||||||||||||
| rm -rf "$TEST_DIR" | ||||||||||||||||
| mkdir -p "$TEST_DIR/home" | ||||||||||||||||
| mkdir -p "$TEST_DIR/bin" | ||||||||||||||||
|
|
||||||||||||||||
| # Mock op | ||||||||||||||||
| cat << 'EOF' > "$TEST_DIR/bin/op" | ||||||||||||||||
| #!/bin/bash | ||||||||||||||||
| if [[ "$1" == "read" ]]; then | ||||||||||||||||
| echo "MOCK PRIVATE KEY CONTENT" | ||||||||||||||||
| elif [[ "$1" == "account" ]]; then | ||||||||||||||||
| exit 0 | ||||||||||||||||
| elif [[ "$1" == "item" && "$2" == "get" ]]; then | ||||||||||||||||
| exit 0 | ||||||||||||||||
| fi | ||||||||||||||||
| EOF | ||||||||||||||||
| chmod +x "$TEST_DIR/bin/op" | ||||||||||||||||
|
|
||||||||||||||||
| # Mock chmod to do nothing, so we can see the permissions at creation | ||||||||||||||||
| cat << 'EOF' > "$TEST_DIR/bin/chmod" | ||||||||||||||||
| #!/bin/bash | ||||||||||||||||
| # no-op | ||||||||||||||||
| echo "MOCK CHMOD: $@" | ||||||||||||||||
| EOF | ||||||||||||||||
| chmod +x "$TEST_DIR/bin/chmod" | ||||||||||||||||
|
|
||||||||||||||||
| export PATH="$TEST_DIR/bin:$PATH" | ||||||||||||||||
| export HOME="$TEST_DIR/home" | ||||||||||||||||
| export XDG_CONFIG_HOME="$HOME/.config" | ||||||||||||||||
|
|
||||||||||||||||
| # Create config | ||||||||||||||||
| mkdir -p "$XDG_CONFIG_HOME/dotfiles" | ||||||||||||||||
| echo "ssh: { vault: 'test', item_name: 'testkey' }" > "$XDG_CONFIG_HOME/dotfiles/config.yaml" | ||||||||||||||||
|
|
||||||||||||||||
| echo "Running setup-ssh-keys.sh with mocked chmod..." | ||||||||||||||||
|
|
||||||||||||||||
| # Run the script | ||||||||||||||||
| ./tools/setup-ssh-keys.sh restore > "$TEST_DIR/output.log" 2>&1 || true | ||||||||||||||||
|
|
||||||||||||||||
| # Check permissions of the private key | ||||||||||||||||
| KEY_FILE="$TEST_DIR/home/.ssh/id_ed25519" | ||||||||||||||||
|
|
||||||||||||||||
| if [[ ! -f "$KEY_FILE" ]]; then | ||||||||||||||||
| echo "FAIL: Key file not found at $KEY_FILE" | ||||||||||||||||
| exit 1 | ||||||||||||||||
| fi | ||||||||||||||||
|
|
||||||||||||||||
| # Get permissions (Linux stat) | ||||||||||||||||
| PERMS=$(stat -c "%a" "$KEY_FILE") | ||||||||||||||||
|
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.
Proposed fix-# Get permissions (Linux stat)
-PERMS=$(stat -c "%a" "$KEY_FILE")
+# Get permissions (portable across Linux and macOS)
+if stat -c "%a" /dev/null >/dev/null 2>&1; then
+ PERMS=$(stat -c "%a" "$KEY_FILE")
+else
+ PERMS=$(stat -f "%Lp" "$KEY_FILE")
+fi📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||
| echo "File permissions detected: $PERMS" | ||||||||||||||||
|
|
||||||||||||||||
| if [[ "$PERMS" == "600" ]]; then | ||||||||||||||||
| echo "SECURE: File created with secure permissions (600)" | ||||||||||||||||
| exit 0 | ||||||||||||||||
| else | ||||||||||||||||
| echo "VULNERABILITY CONFIRMED: File created with insecure permissions ($PERMS)" | ||||||||||||||||
| exit 1 | ||||||||||||||||
| fi | ||||||||||||||||
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 and incorrect date.
Wrong year: Line 1 says
2024-02-12but this PR is from 2026. Should be2026-02-12.Lint failures (from the
Lint Documentationcheck):#). Add a# Sentinel(or similar) H1 heading before the##.Proposed fix
🧰 Tools
🪛 GitHub Check: Lint Documentation
[failure] 4-4: Line length
.jules/sentinel.md:4:81 MD013/line-length Line length [Expected: 80; Actual: 192] 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: 216] 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: 254] 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: "## 2024-02-12 - Insecure SSH K..."] 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: "## 2024-02-12 - Insecure SSH Key Creation (TOCTOU)"] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md022.md
🤖 Prompt for AI Agents