-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsecurity_check.sh
More file actions
executable file
·253 lines (214 loc) · 9.92 KB
/
security_check.sh
File metadata and controls
executable file
·253 lines (214 loc) · 9.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
#!/bin/bash
# Security Check Script
# Detects MongoDB connection strings with embedded credentials and API keys/secrets
# Usage: ./security_check.sh [--verbose]
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Verbose mode flag
VERBOSE=false
if [[ "$1" == "--verbose" ]] || [[ "$1" == "-v" ]]; then
VERBOSE=true
fi
# Track if any issues are found
ISSUES_FOUND=0
GITIGNORE_ISSUES=0
echo -e "${YELLOW}🔒 Running security check for credentials and API keys...${NC}\n"
# Function to check .gitignore for essential entries
check_gitignore() {
local gitignore_file=".gitignore"
local essential_entries=(
".env"
".venv"
"env/"
"venv/"
"ENV/"
"env.bak/"
"venv.bak/"
)
if [ ! -f "$gitignore_file" ]; then
echo -e "${RED}❌ .gitignore file not found!${NC}"
echo -e " ${YELLOW}⚠️ Creating a .gitignore file is essential for security.${NC}\n"
GITIGNORE_ISSUES=1
return
fi
local missing_entries=()
local commented_entries=()
for entry in "${essential_entries[@]}"; do
# Escape dots for regex (but keep / as-is since it's not special in grep -E)
local escaped_entry=$(echo "$entry" | sed 's/\./\\./g')
# Check if entry exists as active (not commented, may have optional leading/trailing whitespace)
# Pattern: optional whitespace, entry, optional whitespace, end of line
if grep -qE "^\s*${escaped_entry}\s*$" "$gitignore_file" 2>/dev/null; then
# Entry exists and is active, skip
continue
fi
# Check if it's commented out (with optional whitespace before #)
# Pattern: optional whitespace, #, optional whitespace, entry, optional whitespace, end of line
if grep -qE "^\s*#\s*${escaped_entry}\s*$" "$gitignore_file" 2>/dev/null; then
commented_entries+=("$entry")
else
missing_entries+=("$entry")
fi
done
if [ ${#missing_entries[@]} -gt 0 ] || [ ${#commented_entries[@]} -gt 0 ]; then
GITIGNORE_ISSUES=1
echo -e "${RED}❌ .gitignore security issues found:${NC}"
if [ ${#missing_entries[@]} -gt 0 ]; then
echo -e " ${YELLOW}Missing entries:${NC}"
for entry in "${missing_entries[@]}"; do
echo -e " - ${RED}$entry${NC}"
done
fi
if [ ${#commented_entries[@]} -gt 0 ]; then
echo -e " ${YELLOW}Commented out entries (should be active):${NC}"
for entry in "${commented_entries[@]}"; do
echo -e " - ${RED}$entry${NC} (currently commented)"
done
fi
echo -e "\n ${YELLOW}⚠️ These entries are essential to prevent committing sensitive files.${NC}"
echo -e " ${YELLOW}⚠️ Please add or uncomment them in your .gitignore file.${NC}\n"
else
if [ "$VERBOSE" = true ]; then
echo -e "${GREEN}✅ .gitignore check passed - all essential entries are present and active${NC}\n"
fi
fi
}
# Check .gitignore first
check_gitignore
# Get the script's own path to exclude it
SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"
SCRIPT_RELATIVE="$(basename "$0")"
# Regex pattern 1: MongoDB URIs with username:password
MONGODB_PATTERN='(mongodb(\+srv)?://[^:]+:[^@]+@)'
# Regex pattern 2: API keys and secrets
# Matches: KEY="value" or KEY=value (non-empty value, at least 4 characters to avoid false positives)
# Pattern 2a: Variables ending with _API_KEY, _SECRET, etc.
# Matches: VAR_API_KEY="value" or VAR_API_KEY=value (value at least 4 chars, allows -_ and other chars)
# Handles both quoted and unquoted values
API_KEY_PATTERN_A='([A-Z_]+(API_KEY|SECRET|PASSWORD|TOKEN|PRIVATE_KEY|ACCESS_KEY|SECRET_KEY|AUTH_TOKEN|SESSION_KEY)\s*=\s*(["\x27][^"\x27]{4,}["\x27]|[^"\x27\s\n]{4,}))'
# Pattern 2b: Standalone KEY=, SECRET=, PASSWORD=, TOKEN= (as whole words, not part of another word)
API_KEY_PATTERN_B='\b(KEY|SECRET|PASSWORD|TOKEN|PRIVATE_KEY|ACCESS_KEY|SECRET_KEY|AUTH_TOKEN|SESSION_KEY)\s*=\s*(["\x27][^"\x27]{4,}["\x27]|[^"\x27\s\n]{4,})'
# Combine both API key patterns
API_KEY_PATTERN="($API_KEY_PATTERN_A|$API_KEY_PATTERN_B)"
# Combine patterns with OR
COMBINED_PATTERN="($MONGODB_PATTERN|$API_KEY_PATTERN)"
# Find all files matching either pattern (excluding common directories)
ALL_MATCHING_FILES=$(grep -r -l -E "$COMBINED_PATTERN" \
--exclude-dir=.git \
--exclude-dir=node_modules \
--exclude-dir=__pycache__ \
--exclude-dir=.venv \
--exclude-dir=venv \
--exclude="*.pyc" \
--exclude="*.lock" \
--exclude="*.log" \
. 2>/dev/null || true)
if [ -z "$ALL_MATCHING_FILES" ]; then
echo -e "${GREEN}✅ No credentials or API keys found in tracked files!${NC}"
exit 0
fi
# Filter files: only check files that are tracked by git and not ignored
FILES_WITH_ISSUES=""
while IFS= read -r file; do
# Skip if file doesn't exist
[ ! -f "$file" ] && continue
# Skip the script itself
if [[ "$file" == *"$SCRIPT_RELATIVE" ]] || [[ "$file" == "$SCRIPT_PATH" ]]; then
continue
fi
# Check if file is ignored by git (.gitignore)
if git check-ignore -q "$file" 2>/dev/null; then
# File is ignored, skip it (e.g., .env files, knowledge_base_kanopy/)
continue
fi
# Check if file is tracked by git (already committed) or staged for commit
# Only report on files that are actually in version control or would be committed
if git ls-files --error-unmatch "$file" >/dev/null 2>&1; then
# File is tracked, include it
if [ -z "$FILES_WITH_ISSUES" ]; then
FILES_WITH_ISSUES="$file"
else
FILES_WITH_ISSUES="$FILES_WITH_ISSUES"$'\n'"$file"
fi
elif git diff --cached --name-only --diff-filter=A | grep -q "^$file$" 2>/dev/null; then
# File is staged for commit (new file), include it
if [ -z "$FILES_WITH_ISSUES" ]; then
FILES_WITH_ISSUES="$file"
else
FILES_WITH_ISSUES="$FILES_WITH_ISSUES"$'\n'"$file"
fi
fi
done <<< "$ALL_MATCHING_FILES"
if [ -z "$FILES_WITH_ISSUES" ]; then
echo -e "${GREEN}✅ No credentials or API keys found in tracked files!${NC}"
exit 0
fi
# Process each file with issues
while IFS= read -r file; do
# Skip if file doesn't exist (can happen with grep)
[ ! -f "$file" ] && continue
ISSUES_FOUND=1
echo -e "${RED}❌ SECURITY ISSUE FOUND:${NC}"
echo -e " File: ${YELLOW}$file${NC}"
if [ "$VERBOSE" = true ]; then
echo -e " Matches:"
# Show MongoDB URI matches (masked)
grep -n -E "$MONGODB_PATTERN" "$file" 2>/dev/null | while IFS=: read -r line_num line_content; do
# Mask the password part for display
masked_line=$(echo "$line_content" | sed -E 's/(mongodb(\+srv)?:\/\/[^:]+:)[^@]+(@)/\1****\2/')
echo -e " ${RED}Line $line_num (MongoDB URI):${NC} $masked_line"
done
# Show API key matches (masked)
grep -n -E "$API_KEY_PATTERN" "$file" 2>/dev/null | while IFS=: read -r line_num line_content; do
# Mask the value part for display - handle both patterns
# First try pattern A (variables ending with _KEY, etc.) - handles quoted and unquoted
masked_line=$(echo "$line_content" | sed -E 's/([A-Z_]+(API_KEY|SECRET|PASSWORD|TOKEN|PRIVATE_KEY|ACCESS_KEY|SECRET_KEY|AUTH_TOKEN|SESSION_KEY)\s*=\s*)(["\x27][^"\x27]{4,}["\x27]|[^"\x27\s\n]{4,})/\1****/')
# If no match, try pattern B (standalone KEY=, etc.) - handles quoted and unquoted
if [[ "$masked_line" == "$line_content" ]]; then
masked_line=$(echo "$line_content" | sed -E 's/(\b(KEY|SECRET|PASSWORD|TOKEN|PRIVATE_KEY|ACCESS_KEY|SECRET_KEY|AUTH_TOKEN|SESSION_KEY)\s*=\s*)(["\x27][^"\x27]{4,}["\x27]|[^"\x27\s\n]{4,})/\1****/')
fi
echo -e " ${RED}Line $line_num (API Key/Secret):${NC} $masked_line"
done
else
# Count occurrences
mongodb_count=$(grep -c -E "$MONGODB_PATTERN" "$file" 2>/dev/null || echo "0")
api_key_count=$(grep -c -E "$API_KEY_PATTERN" "$file" 2>/dev/null || echo "0")
total_count=$((mongodb_count + api_key_count))
if [ "$mongodb_count" -gt 0 ] && [ "$api_key_count" -gt 0 ]; then
echo -e " ${RED}Found $total_count occurrence(s)${NC} (MongoDB: $mongodb_count, API Keys: $api_key_count)"
elif [ "$mongodb_count" -gt 0 ]; then
echo -e " ${RED}Found $mongodb_count MongoDB credential(s)${NC}"
else
echo -e " ${RED}Found $api_key_count API key/secret(s)${NC}"
fi
echo -e " ${YELLOW}Run with --verbose to see details${NC}"
fi
echo ""
done <<< "$FILES_WITH_ISSUES"
# Check if we have any issues (credentials or .gitignore)
if [ $ISSUES_FOUND -eq 1 ] || [ $GITIGNORE_ISSUES -eq 1 ]; then
echo -e "${RED}🚨 SECURITY CHECK FAILED!${NC}"
if [ $ISSUES_FOUND -eq 1 ]; then
echo -e "${YELLOW}⚠️ Credentials or API keys detected in source files.${NC}"
echo -e "${YELLOW}⚠️ Please remove credentials and use environment variables instead.${NC}"
fi
if [ $GITIGNORE_ISSUES -eq 1 ]; then
if [ $ISSUES_FOUND -eq 1 ]; then
echo ""
fi
echo -e "${YELLOW}⚠️ .gitignore file is missing essential entries or has them commented out.${NC}"
fi
echo -e "\n${YELLOW}Best practices:${NC}"
echo -e " 1. Use environment variables: \${MONGODB_URI}, \${VOYAGE_API_KEY}, etc."
echo -e " 2. Store credentials in .env files (and make sure .env files are added to the .gitignore)"
echo -e " 3. Never commit API keys, secrets, or passwords to version control"
echo -e " 4. Ensure .gitignore includes: .env, .venv, env/, venv/, ENV/, env.bak/, venv.bak/"
echo ""
exit 1
fi
echo -e "${GREEN}✅ All security checks passed!${NC}"
exit 0