-
Notifications
You must be signed in to change notification settings - Fork 1
π‘οΈ Sentinel: [CRITICAL] Fix SSH private key creation race condition #17
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-05-22 - [SSH Private Key Race Condition] | ||
|
Check failure on line 1 in .jules/sentinel.md
|
||
| **Vulnerability:** Found a TOCTOU (Time-of-Check to Time-of-Use) race condition in `tools/setup-ssh-keys.sh`. The script created the private key file using output redirection (`>`) which uses the default umask (typically 022), resulting in the file being world-readable for a brief window before `chmod 600` was executed. | ||
|
Check failure on line 2 in .jules/sentinel.md
|
||
| **Learning:** Shell redirection and standard file creation tools respect the current `umask`. Relying on a subsequent `chmod` to secure sensitive files leaves a window of exposure. | ||
|
Check failure on line 3 in .jules/sentinel.md
|
||
| **Prevention:** Always set `umask 077` (or similar restrictive mask) *before* creating sensitive files in shell scripts to ensure they are born secure. Restore the original umask afterwards if necessary. | ||
|
Check failure on line 4 in .jules/sentinel.md
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| #!/bin/bash | ||
| set -e | ||
|
|
||
| # Setup mock environment | ||
| TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| REPO_ROOT="$(cd "$TEST_DIR/.." && pwd)" | ||
| MOCK_BIN="$TEST_DIR/bin" | ||
| TEMP_HOME="$TEST_DIR/temp_home" | ||
|
|
||
| # Clean up previous run | ||
| rm -rf "$TEMP_HOME" | ||
| rm -rf "$MOCK_BIN" | ||
| mkdir -p "$TEMP_HOME" | ||
| mkdir -p "$MOCK_BIN" | ||
|
|
||
| # Mock 'op' command | ||
| cat <<EOF > "$MOCK_BIN/op" | ||
| #!/bin/bash | ||
| if [[ "\$1" == "account" && "\$2" == "list" ]]; then | ||
| exit 0 | ||
| elif [[ "\$1" == "item" && "\$2" == "get" ]]; then | ||
| exit 0 | ||
| elif [[ "\$1" == "read" ]]; then | ||
| if [[ "\$2" == *"private_key"* ]]; then | ||
| echo "PRIVATE KEY CONTENT" | ||
| elif [[ "\$2" == *"public_key"* ]]; then | ||
| echo "PUBLIC KEY CONTENT" | ||
| fi | ||
| fi | ||
| EOF | ||
| chmod +x "$MOCK_BIN/op" | ||
|
|
||
| # Mock 'yq' command (optional, but good to have) | ||
| cat <<EOF > "$MOCK_BIN/yq" | ||
| #!/bin/bash | ||
| exit 1 # simulate not installed or failing, script handles it | ||
| EOF | ||
| chmod +x "$MOCK_BIN/yq" | ||
|
|
||
| # Add mock bin to PATH | ||
| export PATH="$MOCK_BIN:$PATH" | ||
| export HOME="$TEMP_HOME" | ||
| export XDG_CONFIG_HOME="$TEMP_HOME/.config" | ||
|
|
||
| # Run the script | ||
| echo "Running setup-ssh-keys.sh restore..." | ||
| "$REPO_ROOT/tools/setup-ssh-keys.sh" restore | ||
|
|
||
| # Verify files exist | ||
| PRIVATE_KEY="$TEMP_HOME/.ssh/id_ed25519" | ||
| PUBLIC_KEY="$TEMP_HOME/.ssh/id_ed25519.pub" | ||
|
|
||
| if [[ ! -f "$PRIVATE_KEY" ]]; then | ||
| echo "ERROR: Private key not found at $PRIVATE_KEY" | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [[ ! -f "$PUBLIC_KEY" ]]; then | ||
| echo "ERROR: Public key not found at $PUBLIC_KEY" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Verify permissions | ||
| # Private key should be 600 (-rw-------) | ||
| PERMS=$(stat -c "%a" "$PRIVATE_KEY" 2>/dev/null || stat -f "%Lp" "$PRIVATE_KEY") | ||
| if [[ "$PERMS" != "600" ]]; then | ||
| echo "ERROR: Private key permissions are $PERMS, expected 600" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Public key should be 644 (-rw-r--r--) | ||
| PERMS=$(stat -c "%a" "$PUBLIC_KEY" 2>/dev/null || stat -f "%Lp" "$PUBLIC_KEY") | ||
| if [[ "$PERMS" != "644" ]]; then | ||
| echo "ERROR: Public key permissions are $PERMS, expected 644" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "SUCCESS: SSH keys restored with correct permissions." | ||
|
|
||
| # Cleanup | ||
| rm -rf "$TEMP_HOME" | ||
| rm -rf "$MOCK_BIN" |
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 failures (MD041/MD022/MD013) and US spelling.
Line 1 must be an H1 with blank lines, and Lines 2β4 exceed the 80βchar limit; the linter will block the PR. Also prefer βafterwardβ for US English.
β Suggested 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: 203] 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: 180] 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: 321] 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-05-22 - [SSH Private 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-05-22 - [SSH Private Key Race Condition]"] https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md022.md
πͺ LanguageTool
[locale-violation] ~4-~4: In American English, βafterwardβ is the preferred variant. βAfterwardsβ is more commonly used in British English and other dialects.
Context: ...born secure. Restore the original umask afterwards if necessary.
(AFTERWARDS_US)
π€ Prompt for AI Agents