@soulofzephir/pi-skill-pentesting 1.0.2 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
- # Exposed Files Scanner v1.0
2
- # Detects dangerous exposed files and directories
1
+ # Exposed Files Scanner v2.0
2
+ # Detects dangerous exposed files with false positive detection
3
3
 
4
4
  param(
5
5
  [Parameter(Mandatory=$false)]
@@ -11,10 +11,8 @@ param(
11
11
 
12
12
  $ErrorActionPreference = "Continue"
13
13
 
14
- # Get current date
15
14
  $Date = Get-Date -Format "yyyy-MM-dd"
16
15
 
17
- # Parse target URL
18
16
  if ($Target -match "https?://") {
19
17
  $Uri = [System.Uri]$Target
20
18
  $Domain = $Uri.Host
@@ -24,122 +22,61 @@ if ($Target -match "https?://") {
24
22
  $Target = "https://$Target"
25
23
  }
26
24
 
27
- # Create output filename
28
25
  $OutputFile = "$OutputDir/$Domain-exposed-$Date.md"
29
26
 
30
- # ═══════════════════════════════════════════════════════════
31
- # COMMON EXPOSED PATHS
32
- # ═══════════════════════════════════════════════════════════
33
-
34
27
  $ExposedPaths = @(
35
- # Configuration Files
36
- @{ Path = "/.env"; Risk = "CRITICAL"; Desc = "Environment variables - may contain secrets" },
37
- @{ Path = "/.env.local"; Risk = "CRITICAL"; Desc = "Local environment - secrets" },
38
- @{ Path = "/.env.production"; Risk = "CRITICAL"; Desc = "Production environment" },
39
- @{ Path = "/.git/config"; Risk = "CRITICAL"; Desc = "Git repository config - may expose remote" },
40
- @{ Path = "/.git/HEAD"; Risk = "HIGH"; Desc = "Git branch information" },
41
- @{ Path = "/.git/"; Risk = "CRITICAL"; Desc = "Full .git directory exposed" },
42
- @{ Path = "/wp-config.php"; Risk = "CRITICAL"; Desc = "WordPress config - DB + keys" },
43
- @{ Path = "/config.php"; Risk = "CRITICAL"; Desc = "PHP configuration" },
44
- @{ Path = "/settings.py"; Risk = "CRITICAL"; Desc = "Django/Python settings" },
45
- @{ Path = "/config.js"; Risk = "HIGH"; Desc = "Node.js configuration" },
46
- @{ Path = "/application.properties"; Risk = "CRITICAL"; Desc = "Java Spring config" },
47
- @{ Path = "/.htaccess"; Risk = "MEDIUM"; Desc = "Apache config" },
48
- @{ Path = "/.htpasswd"; Risk = "CRITICAL"; Desc = "HTTP Basic Auth hashes" },
49
-
50
- # Backup Files
51
- @{ Path = "/backup.zip"; Risk = "CRITICAL"; Desc = "Compressed backup" },
52
- @{ Path = "/backups.zip"; Risk = "CRITICAL"; Desc = "Compressed backup" },
53
- @{ Path = "/database.zip"; Risk = "CRITICAL"; Desc = "Database backup" },
54
- @{ Path = "/db.zip"; Risk = "CRITICAL"; Desc = "Database backup" },
55
- @{ Path = "/database.sql"; Risk = "CRITICAL"; Desc = "Database dump" },
56
- @{ Path = "/db.sql"; Risk = "CRITICAL"; Desc = "Database dump" },
57
- @{ Path = "/dump.sql"; Risk = "CRITICAL"; Desc = "Database dump" },
58
- @{ Path = "/backup.sql"; Risk = "CRITICAL"; Desc = "Database backup" },
59
- @{ Path = "/site.tar.gz"; Risk = "CRITICAL"; Desc = "Full site backup" },
60
- @{ Path = "/backup.tar.gz"; Risk = "CRITICAL"; Desc = "Full backup archive" },
61
- @{ Path = "/www.zip"; Risk = "CRITICAL"; Desc = "Web root backup" },
62
- @{ Path = "/backup/"; Risk = "HIGH"; Desc = "Backup directory" },
63
- @{ Path = "/backups/"; Risk = "HIGH"; Desc = "Backups directory" },
64
- @{ Path = "/db/"; Risk = "HIGH"; Desc = "Database directory" },
65
- @{ Path = "/*.bak"; Risk = "HIGH"; Desc = "Backup files" },
66
- @{ Path = "/*.backup"; Risk = "HIGH"; Desc = "Backup files" },
67
- @{ Path = "/old/"; Risk = "MEDIUM"; Desc = "Old files directory" },
68
- @{ Path = "/tmp/"; Risk = "MEDIUM"; Desc = "Temporary files" },
69
-
70
- # Admin & Debug Panels
71
- @{ Path = "/admin/"; Risk = "HIGH"; Desc = "Admin panel" },
72
- @{ Path = "/wp-admin/"; Risk = "HIGH"; Desc = "WordPress admin" },
73
- @{ Path = "/administrator/"; Risk = "HIGH"; Desc = "Administrator panel" },
74
- @{ Path = "/manage/"; Risk = "MEDIUM"; Desc = "Management panel" },
75
- @{ Path = "/phpmyadmin/"; Risk = "CRITICAL"; Desc = "Database UI - major exposure" },
76
- @{ Path = "/pma/"; Risk = "CRITICAL"; Desc = "phpMyAdmin alias" },
77
- @{ Path = "/mysql/"; Risk = "CRITICAL"; Desc = "MySQL admin" },
78
- @{ Path = "/debug/"; Risk = "CRITICAL"; Desc = "Debug mode enabled" },
79
- @{ Path = "/api/debug/"; Risk = "CRITICAL"; Desc = "API debug endpoint" },
80
- @{ Path = "/console/"; Risk = "HIGH"; Desc = "Debug console" },
81
- @{ Path = "/debug.php"; Risk = "CRITICAL"; Desc = "Debug script" },
82
- @{ Path = "/test.php"; Risk = "HIGH"; Desc = "Test script" },
83
- @{ Path = "/info.php"; Risk = "HIGH"; Desc = "PHP info exposure" },
84
- @{ Path = "/phpinfo.php"; Risk = "HIGH"; Desc = "PHP info exposure" },
85
-
86
- # Spring Boot Actuator
87
- @{ Path = "/actuator/"; Risk = "HIGH"; Desc = "Spring Boot actuator" },
88
- @{ Path = "/actuator/env"; Risk = "CRITICAL"; Desc = "Environment variables" },
89
- @{ Path = "/actuator/heapdump"; Risk = "CRITICAL"; Desc = "Heap dump - contains secrets" },
90
- @{ Path = "/actuator/threaddump"; Risk = "HIGH"; Desc = "Thread information" },
91
- @{ Path = "/actuator/metrics"; Risk = "MEDIUM"; Desc = "Application metrics" },
92
- @{ Path = "/actuator/configprops"; Risk = "CRITICAL"; Desc = "Configuration properties" },
93
- @{ Path = "/health"; Risk = "MEDIUM"; Desc = "Health check endpoint" },
94
-
95
- # API Documentation
96
- @{ Path = "/swagger/"; Risk = "MEDIUM"; Desc = "Swagger UI" },
97
- @{ Path = "/swagger-ui/"; Risk = "MEDIUM"; Desc = "Swagger documentation" },
98
- @{ Path = "/swagger-ui.html"; Risk = "MEDIUM"; Desc = "Swagger HTML" },
99
- @{ Path = "/api-docs/"; Risk = "MEDIUM"; Desc = "API documentation" },
100
- @{ Path = "/v2/api-docs/"; Risk = "MEDIUM"; Desc = "OpenAPI v2" },
101
- @{ Path = "/v3/api-docs/"; Risk = "MEDIUM"; Desc = "OpenAPI v3" },
102
- @{ Path = "/graphiql/"; Risk = "HIGH"; Desc = "GraphQL IDE" },
103
- @{ Path = "/graphql"; Risk = "MEDIUM"; Desc = "GraphQL endpoint" },
104
- @{ Path = "/api/"; Risk = "LOW"; Desc = "API base path" },
105
- @{ Path = "/api/v1/"; Risk = "LOW"; Desc = "API v1" },
106
-
107
- # Log Files
108
- @{ Path = "/logs/"; Risk = "HIGH"; Desc = "Log directory" },
109
- @{ Path = "/error.log"; Risk = "HIGH"; Desc = "Error log" },
110
- @{ Path = "/access.log"; Risk = "HIGH"; Desc = "Access log" },
111
- @{ Path = "/debug.log"; Risk = "HIGH"; Desc = "Debug log" },
112
- @{ Path = "/application.log"; Risk = "HIGH"; Desc = "Application log" },
113
- @{ Path = "/console.log"; Risk = "MEDIUM"; Desc = "Console log" },
114
-
115
- # Information Disclosure
116
- @{ Path = "/robots.txt"; Risk = "LOW"; Desc = "Reveals hidden paths" },
117
- @{ Path = "/sitemap.xml"; Risk = "LOW"; Desc = "Site structure" },
118
- @{ Path = "/security.txt"; Risk = "LOW"; Desc = "Security contact" },
119
- @{ Path = "/humans.txt"; Risk = "LOW"; Desc = "Developer information" },
120
- @{ Path = "/crossdomain.xml"; Risk = "LOW"; Desc = "Flash policy" },
121
- @{ Path = "/.well-known/security.txt"; Risk = "LOW"; Desc = "Security policy" }
28
+ @{ Path="/.env"; Risk="CRITICAL"; Desc="Environment variables with secrets" },
29
+ @{ Path="/.env.local"; Risk="CRITICAL"; Desc="Local environment" },
30
+ @{ Path="/.git/config"; Risk="CRITICAL"; Desc="Git repository config" },
31
+ @{ Path="/.git/HEAD"; Risk="HIGH"; Desc="Git branch info" },
32
+ @{ Path="/.git/"; Risk="CRITICAL"; Desc="Full .git directory" },
33
+ @{ Path="/wp-config.php"; Risk="CRITICAL"; Desc="WordPress config" },
34
+ @{ Path="/config.php"; Risk="HIGH"; Desc="PHP configuration" },
35
+ @{ Path="/settings.py"; Risk="HIGH"; Desc="Python/Django settings" },
36
+ @{ Path="/config.js"; Risk="HIGH"; Desc="Node.js config" },
37
+ @{ Path="/application.properties"; Risk="CRITICAL"; Desc="Java Spring config" },
38
+ @{ Path="/backup.zip"; Risk="CRITICAL"; Desc="Compressed backup" },
39
+ @{ Path="/backups.zip"; Risk="CRITICAL"; Desc="Compressed backup" },
40
+ @{ Path="/database.sql"; Risk="CRITICAL"; Desc="Database dump" },
41
+ @{ Path="/db.sql"; Risk="CRITICAL"; Desc="Database dump" },
42
+ @{ Path="/dump.sql"; Risk="CRITICAL"; Desc="Database dump" },
43
+ @{ Path="/backup.sql"; Risk="CRITICAL"; Desc="Database backup" },
44
+ @{ Path="/admin/"; Risk="HIGH"; Desc="Admin panel" },
45
+ @{ Path="/wp-admin/"; Risk="HIGH"; Desc="WordPress admin" },
46
+ @{ Path="/administrator/"; Risk="HIGH"; Desc="Admin panel" },
47
+ @{ Path="/phpmyadmin/"; Risk="CRITICAL"; Desc="Database UI" },
48
+ @{ Path="/pma/"; Risk="CRITICAL"; Desc="phpMyAdmin alias" },
49
+ @{ Path="/debug/"; Risk="CRITICAL"; Desc="Debug mode enabled" },
50
+ @{ Path="/api/debug/"; Risk="CRITICAL"; Desc="API debug" },
51
+ @{ Path="/actuator/"; Risk="HIGH"; Desc="Spring Boot actuator" },
52
+ @{ Path="/actuator/env"; Risk="CRITICAL"; Desc="Environment variables" },
53
+ @{ Path="/actuator/heapdump"; Risk="CRITICAL"; Desc="Heap dump" },
54
+ @{ Path="/swagger-ui/"; Risk="MEDIUM"; Desc="API documentation" },
55
+ @{ Path="/swagger/"; Risk="MEDIUM"; Desc="Swagger UI" },
56
+ @{ Path="/graphiql/"; Risk="HIGH"; Desc="GraphQL IDE" },
57
+ @{ Path="/graphql"; Risk="MEDIUM"; Desc="GraphQL endpoint" },
58
+ @{ Path="/logs/"; Risk="HIGH"; Desc="Log directory" },
59
+ @{ Path="/error.log"; Risk="HIGH"; Desc="Error log" },
60
+ @{ Path="/access.log"; Risk="MEDIUM"; Desc="Access log" },
61
+ @{ Path="/robots.txt"; Risk="LOW"; Desc="Reveals paths" },
62
+ @{ Path="/sitemap.xml"; Risk="LOW"; Desc="Site structure" }
122
63
  )
123
64
 
124
- # ═══════════════════════════════════════════════════════════
125
- # SCAN FUNCTION
126
- # ═══════════════════════════════════════════════════════════
127
-
128
- Write-Host ""
129
- Write-Host "╔═══════════════════════════════════════════════════╗" -ForegroundColor Cyan
130
- Write-Host "║ 🔍 Exposed Files Scanner v1.0 ║" -ForegroundColor Cyan
131
- Write-Host "╚═══════════════════════════════════════════════════╝" -ForegroundColor Cyan
132
65
  Write-Host ""
133
- Write-Host "Target: $Target" -ForegroundColor White
66
+ Write-Host "========================================" -ForegroundColor Cyan
67
+ Write-Host " Exposed Files Scanner v2.0" -ForegroundColor Cyan
68
+ Write-Host " Target: $Domain" -ForegroundColor Cyan
69
+ Write-Host "========================================" -ForegroundColor Cyan
134
70
  Write-Host ""
135
71
 
136
- $FoundIssues = @()
72
+ $TrueIssues = @()
73
+ $FalsePositives = @()
137
74
  $Scanned = 0
138
75
 
139
76
  foreach ($item in $ExposedPaths) {
140
77
  $Scanned++
141
78
  $Progress = [math]::Round(($Scanned / $ExposedPaths.Count) * 100)
142
- Write-Progress -Activity "Scanning exposed files..." -Status "$Progress% complete" -PercentComplete $Progress
79
+ Write-Progress -Activity "Scanning..." -Status "$Progress% complete" -PercentComplete $Progress
143
80
 
144
81
  $URL = "$Target$($item.Path)"
145
82
 
@@ -147,187 +84,153 @@ foreach ($item in $ExposedPaths) {
147
84
  $Response = Invoke-WebRequest -Uri $URL -Method Head -TimeoutSec 5 -ErrorAction SilentlyContinue
148
85
 
149
86
  if ($Response.StatusCode -ne 404 -and $Response.StatusCode -ne 403) {
150
- $ContentType = $Response.Headers["Content-Type"] -join ", "
87
+ $ContentType = $Response.Headers["Content-Type"]
151
88
 
152
- $Finding = [PSCustomObject]@{
153
- Path = $item.Path
154
- StatusCode = $Response.StatusCode
155
- Risk = $item.Risk
156
- Description = $item.Desc
157
- ContentType = $ContentType
89
+ # Check for false positive (SPA routing)
90
+ $IsFalsePositive = $false
91
+ if ($item.Path -notmatch "\.(zip|sql|env|tar|gz|bak|backup)" -and
92
+ $ContentType -match "text/html|application/octet-stream") {
93
+ # Check if it's actually HTML content
94
+ try {
95
+ $BodyResp = Invoke-WebRequest -Uri $URL -TimeoutSec 5 -ErrorAction SilentlyContinue
96
+ $Body = $BodyResp.Content.Substring(0, [Math]::Min(500, $BodyResp.Content.Length))
97
+
98
+ if ($Body -match "<html|<!doctype|<head|<body|root|<div" -and $Body.Length -lt 2000) {
99
+ $IsFalsePositive = $true
100
+ }
101
+
102
+ # Check for actual sensitive content
103
+ if ($Body -match "DB_HOST|DB_PASS|PASSWORD|SECRET|API_KEY|aws_key|database|backup") {
104
+ $IsFalsePositive = $false
105
+ }
106
+ } catch {}
158
107
  }
159
- $FoundIssues += $Finding
160
108
 
161
- $Color = switch ($item.Risk) {
162
- "CRITICAL" { "Red" }
163
- "HIGH" { "Yellow" }
164
- "MEDIUM" { "Cyan" }
165
- "LOW" { "Gray" }
109
+ if ($IsFalsePositive) {
110
+ $FalsePositives += $item
111
+ Write-Host "[FP] $($item.Path) (HTTP $($Response.StatusCode)) - Likely SPA" -ForegroundColor Gray
112
+ } else {
113
+ $TrueIssues += $item
114
+ $Color = switch ($item.Risk) {
115
+ "CRITICAL" { "Red" }
116
+ "HIGH" { "Yellow" }
117
+ "MEDIUM" { "Cyan" }
118
+ "LOW" { "Gray" }
119
+ }
120
+ Write-Host "[!] FOUND: $($item.Path) ($($item.Risk))" -ForegroundColor $Color
166
121
  }
167
-
168
- Write-Host "⚠️ FOUND [$($item.Risk)]: $($item.Path)" -ForegroundColor $Color
169
- Write-Host " Status: $($Response.StatusCode) | Type: $($ContentType.Substring(0, [Math]::Min(50, $ContentType.Length)))" -ForegroundColor Gray
170
122
  }
171
- } catch {
172
- # Connection error or timeout - not found
173
- }
123
+ } catch {}
174
124
  }
175
125
 
176
126
  Write-Progress -Activity "Scanning" -Completed
177
127
 
178
- # ═══════════════════════════════════════════════════════════
179
- # SUMMARY
180
- # ═══════════════════════════════════════════════════════════
128
+ $CriticalCount = ($TrueIssues | Where-Object { $_.Risk -eq "CRITICAL" }).Count
129
+ $HighCount = ($TrueIssues | Where-Object { $_.Risk -eq "HIGH" }).Count
130
+ $MediumCount = ($TrueIssues | Where-Object { $_.Risk -eq "MEDIUM" }).Count
131
+ $LowCount = ($TrueIssues | Where-Object { $_.Risk -eq "LOW" }).Count
132
+ $FPCount = $FalsePositives.Count
181
133
 
182
134
  Write-Host ""
183
- Write-Host "═══════════════════════════════════════════════════" -ForegroundColor Cyan
184
- Write-Host "📊 SCAN SUMMARY" -ForegroundColor Cyan
185
- Write-Host "═══════════════════════════════════════════════════" -ForegroundColor Cyan
135
+ Write-Host "========================================" -ForegroundColor Cyan
136
+ Write-Host " SCAN SUMMARY" -ForegroundColor Cyan
137
+ Write-Host "========================================" -ForegroundColor Cyan
186
138
  Write-Host ""
187
-
188
- $CriticalCount = ($FoundIssues | Where-Object { $_.Risk -eq "CRITICAL" }).Count
189
- $HighCount = ($FoundIssues | Where-Object { $_.Risk -eq "HIGH" }).Count
190
- $MediumCount = ($FoundIssues | Where-Object { $_.Risk -eq "MEDIUM" }).Count
191
- $LowCount = ($FoundIssues | Where-Object { $_.Risk -eq "LOW" }).Count
192
-
193
139
  Write-Host "Files Scanned: $Scanned" -ForegroundColor White
194
- Write-Host "Issues Found: $($FoundIssues.Count)" -ForegroundColor Yellow
140
+ Write-Host "True Issues: $($TrueIssues.Count)" -ForegroundColor $(if($TrueIssues.Count -gt 0){"Red"}else{"Green"})
141
+ Write-Host "False Positives: $FPCount" -ForegroundColor Gray
195
142
  Write-Host ""
196
- Write-Host "🔴 CRITICAL: $CriticalCount" -ForegroundColor Red
197
- Write-Host "🟠 HIGH: $HighCount" -ForegroundColor Yellow
198
- Write-Host "🟡 MEDIUM: $MediumCount" -ForegroundColor Cyan
199
- Write-Host "🟢 LOW: $LowCount" -ForegroundColor Gray
200
-
201
- # ═══════════════════════════════════════════════════════════
202
- # GENERATE REPORT
203
- # ═══════════════════════════════════════════════════════════
143
+ Write-Host "CRITICAL: $CriticalCount" -ForegroundColor Red
144
+ Write-Host "HIGH: $HighCount" -ForegroundColor Yellow
145
+ Write-Host "MEDIUM: $MediumCount" -ForegroundColor Cyan
146
+ Write-Host "LOW: $LowCount" -ForegroundColor Gray
147
+
148
+ # Generate Report
149
+ $TrueSection = if ($TrueIssues.Count -gt 0) {
150
+ $t = "| Path | Risk | Description |`n|------|------|-------------|`n"
151
+ foreach ($i in $TrueIssues) {
152
+ $t += "| $($i.Path) | $($i.Risk) | $($i.Desc) |`n"
153
+ }
154
+ $t
155
+ } else {
156
+ "No sensitive files exposed."
157
+ }
204
158
 
205
- if (-not (Test-Path $OutputDir)) {
206
- New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
159
+ $FPSection = if ($FalsePositives.Count -gt 0) {
160
+ $f = "These paths returned HTML/SPA content, not actual sensitive files:`n`n"
161
+ foreach ($i in $FalsePositives) {
162
+ $f += "- $($i.Path) - HTTP 200 (SPA routing)`n"
163
+ }
164
+ $f
165
+ } else {
166
+ "None detected."
207
167
  }
208
168
 
169
+ $Remediation = @()
170
+ if ($CriticalCount -gt 0) { $Remediation += "1. **URGENT**: Remove or protect critical files" }
171
+ if ($HighCount -gt 0) { $Remediation += "2. Add authentication to admin/debug panels" }
172
+ if ($FPCount -gt 0) { $Remediation += "3. (Info) False positives detected - not real issues" }
173
+
209
174
  $Report = @"
210
- # 🔍 Exposed Files Report
175
+ # Exposed Files Report
211
176
 
212
177
  **Target:** $Target
178
+ **Domain:** $Domain
213
179
  **Date:** $Date
214
- **Scanner:** Exposed Files Scanner v1.0
180
+ **Scanner:** Exposed Files Scanner v2.0
181
+ **Author:** Rz (@soulofzephir)
215
182
 
216
183
  ---
217
184
 
218
- ## 📋 Summary
185
+ ## Summary
219
186
 
220
187
  | Metric | Value |
221
188
  |--------|-------|
222
189
  | Files Scanned | $Scanned |
223
- | Issues Found | $($FoundIssues.Count) |
224
- | 🔴 CRITICAL | $CriticalCount |
225
- | 🟠 HIGH | $HighCount |
226
- | 🟡 MEDIUM | $MediumCount |
227
- | 🟢 LOW | $LowCount |
190
+ | True Issues | $($TrueIssues.Count) |
191
+ | False Positives | $FPCount |
192
+ | CRITICAL | $CriticalCount |
193
+ | HIGH | $HighCount |
194
+ | MEDIUM | $MediumCount |
195
+ | LOW | $LowCount |
228
196
 
229
197
  ---
230
198
 
231
- ## 🚨 Critical Issues
232
-
233
- $(if ($CriticalCount -gt 0) {
234
- $FoundIssues | Where-Object { $_.Risk -eq "CRITICAL" } | ForEach-Object {
235
- @"
236
- ### Found: $($_.Path)
237
-
238
- | Field | Value |
239
- |-------|-------|
240
- | Status Code | $($_.StatusCode) |
241
- | Risk Level | 🔴 $($_.Risk) |
242
- | Content Type | $($_.ContentType) |
243
-
244
- **Description:** $($_.Description)
199
+ ## True Security Issues
245
200
 
246
- **Recommendation:** Immediate action required. Remove or restrict access.
201
+ $TrueSection
247
202
 
248
203
  ---
249
- "@
250
- }
251
- } else {
252
- "✅ No critical issues found"
253
- })
254
-
255
- ## 🟠 High Risk Issues
256
-
257
- $(if ($HighCount -gt 0) {
258
- $FoundIssues | Where-Object { $_.Risk -eq "HIGH" } | ForEach-Object {
259
- @"
260
- - **$($_.Path)** - $($_.Description) (HTTP $($_.StatusCode))
261
- "@
262
- }
263
- } else {
264
- "✅ No high-risk issues found"
265
- })
266
-
267
- ## 🟡 Medium Risk Issues
268
-
269
- $(if ($MediumCount -gt 0) {
270
- $FoundIssues | Where-Object { $_.Risk -eq "MEDIUM" } | ForEach-Object {
271
- @"
272
- - **$($_.Path)** - $($_.Description) (HTTP $($_.StatusCode))
273
- "@
274
- }
275
- } else {
276
- "✅ No medium-risk issues found"
277
- })
278
-
279
- ## 🟢 Low Risk Issues
280
-
281
- $(if ($LowCount -gt 0) {
282
- $FoundIssues | Where-Object { $_.Risk -eq "LOW" } | ForEach-Object {
283
- @"
284
- - **$($_.Path)** - $($_.Description) (HTTP $($_.StatusCode))
285
- "@
286
- }
287
- } else {
288
- "✅ No low-risk issues found"
289
- })
290
204
 
291
- ---
292
-
293
- ## 📝 All Findings
205
+ ## False Positives
294
206
 
295
- | Path | Status | Risk | Description |
296
- |------|--------|------|-------------|
297
- $(foreach ($issue in $FoundIssues) {
298
- "| $($issue.Path) | $($issue.StatusCode) | $($issue.Risk) | $($issue.Description) |"
299
- })
207
+ $FPSection
300
208
 
301
209
  ---
302
210
 
303
- ## 🛡️ Remediation Checklist
211
+ ## Remediation
304
212
 
305
- - [ ] Block .env files in web server config
306
- - [ ] Disable .git directory listing
307
- - [ ] Remove backup files from web root
308
- - [ ] Protect admin panels with IP restriction
309
- - [ ] Disable debug mode in production
310
- - [ ] Secure Spring Boot actuator endpoints
311
- - [ ] Add authentication to API documentation
312
- - [ ] Disable directory listing
313
- - [ ] Remove test/debug files
213
+ $(if ($Remediation.Count -gt 0) { $Remediation -join "`n" } else { "No immediate action required." })
314
214
 
315
215
  ---
316
216
 
317
- **Report Generated:** $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")
217
+ **Generated:** $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
318
218
  "@
319
219
 
320
- # Save report
220
+ if (-not (Test-Path $OutputDir)) {
221
+ New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
222
+ }
223
+
321
224
  $Report | Out-File -FilePath $OutputFile -Encoding UTF8
322
225
 
323
226
  Write-Host ""
324
- Write-Host "═══════════════════════════════════════════════════" -ForegroundColor Cyan
325
- Write-Host "Scan Complete!" -ForegroundColor Green
326
- Write-Host "═══════════════════════════════════════════════════" -ForegroundColor Cyan
227
+ Write-Host "========================================" -ForegroundColor Green
228
+ Write-Host " Scan Complete!" -ForegroundColor Green
229
+ Write-Host "========================================" -ForegroundColor Green
327
230
  Write-Host ""
328
- Write-Host "📄 Report: $OutputFile" -ForegroundColor White
231
+ Write-Host "Report: $OutputFile" -ForegroundColor White
329
232
  Write-Host ""
330
233
 
331
234
  if ($CriticalCount -gt 0) {
332
- Write-Host "⚠️ IMMEDIATE ACTION REQUIRED for critical findings!" -ForegroundColor Red
235
+ Write-Host "IMMEDIATE ACTION REQUIRED!" -ForegroundColor Red
333
236
  }