From ca0975b5892c4fd57dc5fed971f99588332f0c3a Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 04:39:59 +0000 Subject: [PATCH] fix(security): prevent TOCTOU race condition in SSH key creation - Use `umask 077` in a subshell when creating `.ssh` directory and private key files. - Ensures files are created with restricted permissions from the start, closing the race condition window where they might be world-readable. - Add security journal entry in `.jules/sentinel.md`. Co-authored-by: kidchenko <5432753+kidchenko@users.noreply.github.com> --- .jules/sentinel.md | 4 ++++ tools/setup-ssh-keys.sh | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 .jules/sentinel.md diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..d29fab4 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2024-05-22 - TOCTOU Race Condition in File Permissions +**Vulnerability:** SSH private keys were written to disk with default permissions and then restricted with `chmod` immediately after. This creates a Time-of-Check-Time-of-Use (TOCTOU) race condition window where the file is world-readable (depending on system umask). +**Learning:** `chmod` is not atomic with file creation. Relying on it for sensitive files leaves a security gap. +**Prevention:** Use `umask` in a subshell or the `install` command (if portable) to ensure files are created with restrictive permissions from the start. Example: `(umask 077; echo secret > file)` diff --git a/tools/setup-ssh-keys.sh b/tools/setup-ssh-keys.sh index bde52fd..82bdc80 100755 --- a/tools/setup-ssh-keys.sh +++ b/tools/setup-ssh-keys.sh @@ -148,12 +148,20 @@ cmd_restore() { say "Restoring SSH key from 1Password..." - # Create SSH directory - mkdir -p "$SSH_DIR" + # Create SSH directory securely + if [[ ! -d "$SSH_DIR" ]]; then + ( + umask 077 + mkdir -p "$SSH_DIR" + ) + fi chmod 700 "$SSH_DIR" - # Read private key from 1Password and save locally - op read "op://$VAULT/$KEY_NAME/private_key" > "$PRIVATE_KEY_FILE" + # Read private key from 1Password and save locally securely + ( + 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