Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions references/check-catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,12 @@ severity, description, and remediation.
- **Description:** Changes to permission rules are not logged. Malicious permission escalation cannot be detected after the fact.
- **Remediation:** Enable audit logging for permission changes.

### CHK-PRM-013 -- SSH private key has overly permissive permissions
- **Severity:** Critical
- **Description:** SSH private key files (e.g., `~/.ssh/id_rsa`, `~/.ssh/id_ed25519`) have permissions more permissive than 600. SSH clients often refuse to use keys with incorrect permissions, and they can be read by other users on the system.
- **Remediation:** Set SSH key permissions to 600 (read/write owner only): `chmod 600 ~/.ssh/id_rsa`
- **Auto-fix:** `chmod 600 "$KEY_PATH"`

---

## Cron (CHK-CRN)
Expand Down
50 changes: 50 additions & 0 deletions scripts/helpers/test_integration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,55 @@ test_chmod_600() {
[[ "$perms" == "600" ]]
}

# ---------------------------------------------------------------------------
# Test: CHK-PRM-013 auto-fix (SSH private key permissions)
# ---------------------------------------------------------------------------
test_prm_013() {
# Create mock SSH directory
local ssh_dir="${TEST_DIR}/.ssh"
mkdir -p "$ssh_dir"

# Create test SSH private keys
local test_key="${ssh_dir}/id_test_rsa"
local test_pem="${ssh_dir}/test.pem"

cat > "$test_key" <<'EOF'
-----BEGIN RSA PRIVATE KEY-----
fake key content
-----END RSA PRIVATE KEY-----
EOF

cat > "$test_pem" <<'EOF'
-----BEGIN PRIVATE KEY-----
fake pem content
-----END PRIVATE KEY-----
EOF

for key_file in "$test_key" "$test_pem"; do
# Set insecure permissions
chmod 644 "$key_file"

# Run the auto-fix command
chmod 600 "$key_file"

# Verify permissions were fixed
local perms
if [[ "$(uname -s)" == "Darwin" ]]; then
perms=$(stat -f "%Lp" "$key_file")
else
perms=$(stat -c "%a" "$key_file")
fi

if [[ "$perms" != "600" ]]; then
return 1
fi
done
# NOTE: This test verifies the chmod auto-fix command works correctly, but
# does not exercise the scanner's find/detect logic itself. This is
# consistent with other integration tests in this file which focus on
# auto-fix command validation rather than scanner detection coverage.
}

# ---------------------------------------------------------------------------
# Main test execution
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -336,6 +385,7 @@ run_test "CHK-CFG-010: Enable sensitive data redaction" "test_cfg_010"
run_test "CHK-CFG-011: Enable browser restrictions" "test_cfg_011"
run_test "CHK-CFG-012: Disable network discovery" "test_cfg_012"
run_test "File permissions: chmod 600" "test_chmod_600"
run_test "CHK-PRM-013: Fix SSH key permissions" "test_prm_013"

echo "─────────────────────────────────────────────────────────────────────────────"
echo ""
Expand Down
57 changes: 57 additions & 0 deletions scripts/scan_permissions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,62 @@ check_cloud_sync() {
fi
}

# ─── CHK-PRM-013: SSH private key permissions ───────────────────────────────

check_ssh_keys() {
log_info "CHK-PRM-013: Checking SSH private key permissions"

local ssh_dir="$HOME/.ssh"
local found=0

if [[ ! -d "$ssh_dir" ]]; then
add_finding "CHK-PRM-013" "info" \
"No SSH directory found" \
"No ~/.ssh directory exists on this system" "" "" ""
return
fi

# Search for id_* files and *.pem files
while IFS= read -r -d '' f; do
found=1
local perms
perms="$(get_perms "$f")"
[[ -z "$perms" ]] && continue

if [[ "$perms" != "600" ]]; then
# Validate filename contains only safe characters before using in auto_fix.
# The safe_exec whitelist pattern for chmod requires paths matching
# [a-zA-Z0-9/._-]+, so we must not emit auto_fix for filenames with
# characters outside that set (e.g., spaces, quotes, shell metacharacters).
# Standard SSH key names (id_rsa, id_ed25519, *.pem) always pass this check.
local auto_fix_cmd="" remediation_msg="Manual fix required: chmod 600 [file]"
if [[ "$f" =~ ^[a-zA-Z0-9/._-]+$ ]]; then
auto_fix_cmd="chmod 600 $f"
remediation_msg="Run: chmod 600 $f"
fi
add_finding "CHK-PRM-013" "critical" \
"SSH private key has insecure permissions" \
"SSH private keys must be chmod 600 or SSH clients will refuse to use them. Current: $perms" \
"$f mode $perms" \
"$remediation_msg" \
"$auto_fix_cmd"
else
add_finding "CHK-PRM-013" "ok" \
"SSH private key permissions correct" \
"SSH private key is properly restricted to owner read/write" \
"$f mode $perms" "" ""
fi
done < <(find "$ssh_dir" -maxdepth 1 \( \
-iname 'id_*' -o -iname '*.pem' \
\) -type f ! -iname '*.pub' -print0 2>/dev/null)

if [[ "$found" -eq 0 ]]; then
add_finding "CHK-PRM-013" "info" \
"No SSH private keys found" \
"No SSH private key files detected in ~/.ssh directory" "" "" ""
fi
}

# ─── Run all checks ─────────────────────────────────────────────────────────

main() {
Expand All @@ -663,6 +719,7 @@ main() {
check_credentials_dir
check_log_secrets
check_cloud_sync
check_ssh_keys

log_info "Permissions scan complete: ${#FINDINGS[@]} finding(s)"

Expand Down