diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..147bfa5 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,14 @@ +## 2026-02-17 - Insecure Temporary Files & Shell Argument Injection +**Vulnerability:** +1. Backup script created directories and files in default umask (likely 755/644), exposing sensitive source code backups to other users. +2. Shell script passed exclude patterns as a space-separated string to `zip`, causing incorrect argument parsing if patterns contained spaces (argument injection/logic error). + +**Learning:** +- Always explicitly set directory permissions (`chmod 700`) for sensitive data directories. +- Use `umask 077` in a subshell when creating sensitive files to ensure they are private by default (0600). +- In Bash, always use arrays (`"${arr[@]}"`) for passing lists of arguments to commands to handle spaces correctly. String concatenation is dangerous. + +**Prevention:** +- Use `install -d -m 700` or `mkdir` + `chmod 700` for private directories. +- Review all shell scripts for unquoted variable expansions in command arguments. +- Prefer array handling over string manipulation for command arguments. diff --git a/tools/backup-projects.sh b/tools/backup-projects.sh index 1b7f6d2..a76b1b7 100755 --- a/tools/backup-projects.sh +++ b/tools/backup-projects.sh @@ -232,15 +232,6 @@ parse_args() { done } -# --- Build Exclude Arguments for Zip --- -build_exclude_args() { - local args=() - for pattern in "${EXCLUDE_PATTERNS[@]}"; do - args+=("-x" "*/${pattern}/*" "-x" "*/${pattern}") - done - echo "${args[@]}" -} - # --- Git Sync --- sync_git_repos() { say "Syncing git repositories..." @@ -350,11 +341,19 @@ cmd_backup() { # Setup directories if [[ "$DRY_RUN" != true ]]; then - mkdir -p "$BACKUP_TEMP_DIR" - mkdir -p "$LOG_DIR" + # Ensure directories exist with secure permissions (0700) + if [[ ! -d "$BACKUP_TEMP_DIR" ]]; then + mkdir -p "$BACKUP_TEMP_DIR" + chmod 700 "$BACKUP_TEMP_DIR" + fi + + if [[ ! -d "$LOG_DIR" ]]; then + mkdir -p "$LOG_DIR" + chmod 700 "$LOG_DIR" + fi else - debug "Would create: $BACKUP_TEMP_DIR" - debug "Would create: $LOG_DIR" + debug "Would create: $BACKUP_TEMP_DIR (0700)" + debug "Would create: $LOG_DIR (0700)" fi # Sync git repositories first @@ -406,17 +405,21 @@ cmd_backup() { done fi else - local exclude_args - exclude_args=$(build_exclude_args) + # Build exclude arguments for zip + local exclude_args=() + for pattern in "${EXCLUDE_PATTERNS[@]}"; do + exclude_args+=("-x" "*/${pattern}/*" "-x" "*/${pattern}") + done ( cd "$HOME" || exit 1 + # Set umask to 077 so created files are 0600 (owner read/write only) + umask 077 + if [[ "$VERBOSE" == true ]]; then - # shellcheck disable=SC2086 - zip -r "$archive_path" "${relative_paths[@]}" $exclude_args + zip -r "$archive_path" "${relative_paths[@]}" "${exclude_args[@]}" else - # shellcheck disable=SC2086 - zip -r -q "$archive_path" "${relative_paths[@]}" $exclude_args + zip -r -q "$archive_path" "${relative_paths[@]}" "${exclude_args[@]}" fi )