flareguard 0.1.0
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.
- package/Cargo.lock +2962 -0
- package/Cargo.toml +66 -0
- package/LICENSE +21 -0
- package/README.md +115 -0
- package/bin/flareguard.js +78 -0
- package/package.json +50 -0
- package/scripts/postinstall.mjs +83 -0
- package/src/bindings/ast_scanner.rs +950 -0
- package/src/bindings/cli.rs +49 -0
- package/src/bindings/jsonc.rs +166 -0
- package/src/bindings/mod.rs +7 -0
- package/src/bindings/reporter.rs +328 -0
- package/src/bindings/types.rs +129 -0
- package/src/bindings/validator.rs +227 -0
- package/src/bindings/wrangler.rs +647 -0
- package/src/cli.rs +77 -0
- package/src/lib.rs +7 -0
- package/src/main.rs +451 -0
- package/src/origin/cli.rs +92 -0
- package/src/origin/cloudflare.rs +170 -0
- package/src/origin/confidence.rs +320 -0
- package/src/origin/crtsh.rs +144 -0
- package/src/origin/dns.rs +177 -0
- package/src/origin/enumerator.rs +271 -0
- package/src/origin/error.rs +19 -0
- package/src/origin/mock.rs +320 -0
- package/src/origin/mod.rs +19 -0
- package/src/origin/models.rs +167 -0
- package/src/origin/prober.rs +260 -0
- package/src/origin/remediation.rs +73 -0
- package/src/origin/report.rs +625 -0
- package/src/origin/scanner.rs +217 -0
- package/src/secrets/cli.rs +94 -0
- package/src/secrets/env_parser.rs +464 -0
- package/src/secrets/ignore.rs +139 -0
- package/src/secrets/mod.rs +14 -0
- package/src/secrets/report/json_format.rs +97 -0
- package/src/secrets/report/mod.rs +48 -0
- package/src/secrets/report/sarif.rs +225 -0
- package/src/secrets/report/text.rs +105 -0
- package/src/secrets/rules/builtin.rs +280 -0
- package/src/secrets/rules/entropy.rs +66 -0
- package/src/secrets/rules/mod.rs +7 -0
- package/src/secrets/rules/types.rs +183 -0
- package/src/secrets/scanner.rs +444 -0
- package/src/zone/cli.rs +111 -0
- package/src/zone/client/cf_client.rs +405 -0
- package/src/zone/client/mod.rs +5 -0
- package/src/zone/client/provider.rs +12 -0
- package/src/zone/mock_data.rs +481 -0
- package/src/zone/mod.rs +125 -0
- package/src/zone/models/audit.rs +194 -0
- package/src/zone/models/cloudflare.rs +252 -0
- package/src/zone/models/mod.rs +7 -0
- package/src/zone/models/sarif.rs +89 -0
- package/src/zone/reporters/html_rep.rs +345 -0
- package/src/zone/reporters/json_rep.rs +7 -0
- package/src/zone/reporters/mod.rs +9 -0
- package/src/zone/reporters/sarif_rep.rs +100 -0
- package/src/zone/reporters/terminal.rs +322 -0
- package/src/zone/rules/definitions.rs +201 -0
- package/src/zone/rules/evaluator.rs +484 -0
- package/src/zone/rules/mod.rs +5 -0
- package/src/zone/scoring.rs +104 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
use crate::zone::models::{AggregateAuditReport, RiskLevel};
|
|
2
|
+
use colored::*;
|
|
3
|
+
use comfy_table::modifiers::UTF8_ROUND_CORNERS;
|
|
4
|
+
use comfy_table::presets::UTF8_FULL;
|
|
5
|
+
use comfy_table::{Attribute, Cell, CellAlignment, Color, ContentArrangement, Table};
|
|
6
|
+
|
|
7
|
+
pub fn render_terminal(report: &AggregateAuditReport, verbose: bool) -> String {
|
|
8
|
+
let mut out = String::new();
|
|
9
|
+
|
|
10
|
+
// 1. Executive Header Banner
|
|
11
|
+
out.push_str(&format!(
|
|
12
|
+
"\n{}\n",
|
|
13
|
+
"╔══════════════════════════════════════════════════════════════════════════════╗"
|
|
14
|
+
.cyan()
|
|
15
|
+
.bold()
|
|
16
|
+
));
|
|
17
|
+
out.push_str(&format!(
|
|
18
|
+
"║ {} ║\n",
|
|
19
|
+
"🛡️ CLOUDFLARE ZONE SECURITY AUDITOR (cf-zone-auditor)"
|
|
20
|
+
.bright_white()
|
|
21
|
+
.bold()
|
|
22
|
+
));
|
|
23
|
+
out.push_str(&format!(
|
|
24
|
+
"║ {} ║\n",
|
|
25
|
+
" Posture Assessment & Compliance Enforcement Suite".dimmed()
|
|
26
|
+
));
|
|
27
|
+
out.push_str(&format!(
|
|
28
|
+
"{}\n\n",
|
|
29
|
+
"╚══════════════════════════════════════════════════════════════════════════════╝"
|
|
30
|
+
.cyan()
|
|
31
|
+
.bold()
|
|
32
|
+
));
|
|
33
|
+
|
|
34
|
+
// 2. Executive Score Card & Summary
|
|
35
|
+
let grade_colored = match report.overall_grade.as_str() {
|
|
36
|
+
"A+" => "A+ (EXCELLENT)".bright_green().bold(),
|
|
37
|
+
"A" => "A (STRONG)".bright_green().bold(),
|
|
38
|
+
"B" => "B (GOOD)".green().bold(),
|
|
39
|
+
"C" => "C (MODERATE RISK)".yellow().bold(),
|
|
40
|
+
"D" => "D (HIGH RISK)".bright_yellow().bold(),
|
|
41
|
+
_ => "F (CRITICAL VULNERABILITIES)".bright_red().bold(),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
let score_colored = if report.average_score >= 90.0 {
|
|
45
|
+
format!("{:.1} / 100", report.average_score)
|
|
46
|
+
.bright_green()
|
|
47
|
+
.bold()
|
|
48
|
+
} else if report.average_score >= 80.0 {
|
|
49
|
+
format!("{:.1} / 100", report.average_score).green().bold()
|
|
50
|
+
} else if report.average_score >= 70.0 {
|
|
51
|
+
format!("{:.1} / 100", report.average_score).yellow().bold()
|
|
52
|
+
} else {
|
|
53
|
+
format!("{:.1} / 100", report.average_score)
|
|
54
|
+
.bright_red()
|
|
55
|
+
.bold()
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
out.push_str(&format!(
|
|
59
|
+
" 📊 {} {}\n",
|
|
60
|
+
"Audited Timestamp:".dimmed(),
|
|
61
|
+
report.timestamp.to_rfc3339()
|
|
62
|
+
));
|
|
63
|
+
if let Some(ref acc) = report.account_id {
|
|
64
|
+
out.push_str(&format!(" 🏢 {} {}\n", "Account ID:".dimmed(), acc));
|
|
65
|
+
}
|
|
66
|
+
out.push_str(&format!(
|
|
67
|
+
" 🌐 {} {}\n",
|
|
68
|
+
"Total Zones Audited:".dimmed(),
|
|
69
|
+
report.total_zones.to_string().bold()
|
|
70
|
+
));
|
|
71
|
+
out.push_str(&format!(
|
|
72
|
+
" 🏆 {} {}\n",
|
|
73
|
+
"Account Security Score:".dimmed(),
|
|
74
|
+
score_colored
|
|
75
|
+
));
|
|
76
|
+
out.push_str(&format!(
|
|
77
|
+
" 🎖️ {} {}\n",
|
|
78
|
+
"Overall Health Grade:".dimmed(),
|
|
79
|
+
grade_colored
|
|
80
|
+
));
|
|
81
|
+
out.push_str(&format!(
|
|
82
|
+
" 🚨 {} [ {} {} | {} {} | {} {} | {} {} | {} {} ]\n\n",
|
|
83
|
+
"Findings Summary:".dimmed(),
|
|
84
|
+
report
|
|
85
|
+
.total_findings
|
|
86
|
+
.critical
|
|
87
|
+
.to_string()
|
|
88
|
+
.bright_red()
|
|
89
|
+
.bold(),
|
|
90
|
+
"CRITICAL".bright_red(),
|
|
91
|
+
report
|
|
92
|
+
.total_findings
|
|
93
|
+
.high
|
|
94
|
+
.to_string()
|
|
95
|
+
.bright_yellow()
|
|
96
|
+
.bold(),
|
|
97
|
+
"HIGH".bright_yellow(),
|
|
98
|
+
report.total_findings.medium.to_string().yellow(),
|
|
99
|
+
"MEDIUM".yellow(),
|
|
100
|
+
report.total_findings.low.to_string().cyan(),
|
|
101
|
+
"LOW".cyan(),
|
|
102
|
+
report.total_findings.info.to_string().white(),
|
|
103
|
+
"INFO".white(),
|
|
104
|
+
));
|
|
105
|
+
|
|
106
|
+
// 3. Multi-Zone Posture Overview Table
|
|
107
|
+
let mut table = Table::new();
|
|
108
|
+
table
|
|
109
|
+
.load_preset(UTF8_FULL)
|
|
110
|
+
.apply_modifier(UTF8_ROUND_CORNERS)
|
|
111
|
+
.set_content_arrangement(ContentArrangement::Dynamic)
|
|
112
|
+
.set_header(vec![
|
|
113
|
+
Cell::new("Zone Name").add_attribute(Attribute::Bold),
|
|
114
|
+
Cell::new("Plan").add_attribute(Attribute::Bold),
|
|
115
|
+
Cell::new("SSL Mode").add_attribute(Attribute::Bold),
|
|
116
|
+
Cell::new("Min TLS").add_attribute(Attribute::Bold),
|
|
117
|
+
Cell::new("Always HTTPS").add_attribute(Attribute::Bold),
|
|
118
|
+
Cell::new("HSTS").add_attribute(Attribute::Bold),
|
|
119
|
+
Cell::new("WAF").add_attribute(Attribute::Bold),
|
|
120
|
+
Cell::new("DNSSEC").add_attribute(Attribute::Bold),
|
|
121
|
+
Cell::new("Score")
|
|
122
|
+
.add_attribute(Attribute::Bold)
|
|
123
|
+
.set_alignment(CellAlignment::Center),
|
|
124
|
+
Cell::new("Grade")
|
|
125
|
+
.add_attribute(Attribute::Bold)
|
|
126
|
+
.set_alignment(CellAlignment::Center),
|
|
127
|
+
]);
|
|
128
|
+
|
|
129
|
+
for z in &report.zone_reports {
|
|
130
|
+
let ssl_cell = format_ssl_cell(&z.settings_summary.ssl_mode);
|
|
131
|
+
let tls_cell = format_tls_cell(&z.settings_summary.min_tls);
|
|
132
|
+
let https_cell = format_bool_cell(&z.settings_summary.always_https);
|
|
133
|
+
let hsts_cell = format_bool_cell(&z.settings_summary.hsts_status);
|
|
134
|
+
let waf_cell = format_bool_cell(&z.settings_summary.waf_status);
|
|
135
|
+
let dnssec_cell = format_dnssec_cell(&z.settings_summary.dnssec_status);
|
|
136
|
+
let score_cell = format_score_cell(z.score);
|
|
137
|
+
let grade_cell = format_grade_cell(&z.grade);
|
|
138
|
+
|
|
139
|
+
table.add_row(vec![
|
|
140
|
+
Cell::new(&z.zone_name).add_attribute(Attribute::Bold),
|
|
141
|
+
Cell::new(&z.plan_name),
|
|
142
|
+
ssl_cell,
|
|
143
|
+
tls_cell,
|
|
144
|
+
https_cell,
|
|
145
|
+
hsts_cell,
|
|
146
|
+
waf_cell,
|
|
147
|
+
dnssec_cell,
|
|
148
|
+
score_cell,
|
|
149
|
+
grade_cell,
|
|
150
|
+
]);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
out.push_str(&table.to_string());
|
|
154
|
+
out.push_str("\n\n");
|
|
155
|
+
|
|
156
|
+
// 4. Detailed Findings Breakdown (if there are findings or verbose mode)
|
|
157
|
+
let has_any_findings = report.zone_reports.iter().any(|z| !z.findings.is_empty());
|
|
158
|
+
if has_any_findings {
|
|
159
|
+
out.push_str(&format!(
|
|
160
|
+
"{}\n",
|
|
161
|
+
"🔍 DETAILED SECURITY FINDINGS & REMEDIATION PLAN"
|
|
162
|
+
.bright_cyan()
|
|
163
|
+
.bold()
|
|
164
|
+
));
|
|
165
|
+
out.push_str(&format!(
|
|
166
|
+
"{}\n\n",
|
|
167
|
+
"──────────────────────────────────────────────────────────────────────────────"
|
|
168
|
+
.dimmed()
|
|
169
|
+
));
|
|
170
|
+
|
|
171
|
+
for z in &report.zone_reports {
|
|
172
|
+
if z.findings.is_empty() {
|
|
173
|
+
if verbose {
|
|
174
|
+
out.push_str(&format!(
|
|
175
|
+
" ✅ {}: {} (Score: {}/100, Grade: {})\n\n",
|
|
176
|
+
z.zone_name.bold(),
|
|
177
|
+
"All security checks passed with zero findings!".bright_green(),
|
|
178
|
+
z.score,
|
|
179
|
+
z.grade.bright_green()
|
|
180
|
+
));
|
|
181
|
+
}
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
out.push_str(&format!(
|
|
186
|
+
" 📁 Zone: {} [ Score: {} | Grade: {} | {} findings ]\n",
|
|
187
|
+
z.zone_name.bright_white().bold(),
|
|
188
|
+
format_score_text(z.score),
|
|
189
|
+
z.grade.bold(),
|
|
190
|
+
z.findings.len()
|
|
191
|
+
));
|
|
192
|
+
|
|
193
|
+
let mut finding_table = Table::new();
|
|
194
|
+
finding_table
|
|
195
|
+
.load_preset(UTF8_FULL)
|
|
196
|
+
.apply_modifier(UTF8_ROUND_CORNERS)
|
|
197
|
+
.set_content_arrangement(ContentArrangement::Dynamic)
|
|
198
|
+
.set_header(vec![
|
|
199
|
+
Cell::new("ID").add_attribute(Attribute::Bold),
|
|
200
|
+
Cell::new("Severity").add_attribute(Attribute::Bold),
|
|
201
|
+
Cell::new("Title & Finding").add_attribute(Attribute::Bold),
|
|
202
|
+
Cell::new("Current vs Expected").add_attribute(Attribute::Bold),
|
|
203
|
+
Cell::new("Remediation Guidance").add_attribute(Attribute::Bold),
|
|
204
|
+
]);
|
|
205
|
+
|
|
206
|
+
for f in &z.findings {
|
|
207
|
+
let sev_cell = match f.risk_level {
|
|
208
|
+
RiskLevel::Critical => Cell::new("CRITICAL")
|
|
209
|
+
.fg(Color::Red)
|
|
210
|
+
.add_attribute(Attribute::Bold),
|
|
211
|
+
RiskLevel::High => Cell::new("HIGH")
|
|
212
|
+
.fg(Color::Yellow)
|
|
213
|
+
.add_attribute(Attribute::Bold),
|
|
214
|
+
RiskLevel::Medium => Cell::new("MEDIUM").fg(Color::Yellow),
|
|
215
|
+
RiskLevel::Low => Cell::new("LOW").fg(Color::Cyan),
|
|
216
|
+
RiskLevel::Info => Cell::new("INFO").fg(Color::White),
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
let desc_text = format!("{}\n{}", f.title.bold(), f.description.dimmed());
|
|
220
|
+
let value_text = format!(
|
|
221
|
+
"Actual: {}\nExpected: {}",
|
|
222
|
+
f.actual_value, f.expected_value
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
finding_table.add_row(vec![
|
|
226
|
+
Cell::new(&f.rule_id).add_attribute(Attribute::Bold),
|
|
227
|
+
sev_cell,
|
|
228
|
+
Cell::new(desc_text),
|
|
229
|
+
Cell::new(value_text),
|
|
230
|
+
Cell::new(&f.remediation),
|
|
231
|
+
]);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
out.push_str(&finding_table.to_string());
|
|
235
|
+
out.push_str("\n\n");
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
out.push_str(&format!(
|
|
239
|
+
"🎉 {}\n\n",
|
|
240
|
+
"EXCELLENT: All audited zones passed 100% of security posture checks!"
|
|
241
|
+
.bright_green()
|
|
242
|
+
.bold()
|
|
243
|
+
));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
out
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
fn format_ssl_cell(mode: &str) -> Cell {
|
|
250
|
+
let m = mode.to_lowercase();
|
|
251
|
+
if m == "strict" {
|
|
252
|
+
Cell::new("strict").fg(Color::Green)
|
|
253
|
+
} else if m == "full" {
|
|
254
|
+
Cell::new("full").fg(Color::Yellow)
|
|
255
|
+
} else {
|
|
256
|
+
Cell::new(&m).fg(Color::Red).add_attribute(Attribute::Bold)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
fn format_tls_cell(tls: &str) -> Cell {
|
|
261
|
+
if tls.contains("1.3") || tls.contains("1.2") {
|
|
262
|
+
Cell::new(tls).fg(Color::Green)
|
|
263
|
+
} else {
|
|
264
|
+
Cell::new(tls).fg(Color::Red).add_attribute(Attribute::Bold)
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
fn format_bool_cell(status: &str) -> Cell {
|
|
269
|
+
let s = status.to_lowercase();
|
|
270
|
+
if s == "enabled" || s == "active" || s == "on" || s == "true" {
|
|
271
|
+
Cell::new("Enabled").fg(Color::Green)
|
|
272
|
+
} else {
|
|
273
|
+
Cell::new("Disabled").fg(Color::Red)
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
fn format_dnssec_cell(status: &str) -> Cell {
|
|
278
|
+
let s = status.to_lowercase();
|
|
279
|
+
if s == "active" {
|
|
280
|
+
Cell::new("Active").fg(Color::Green)
|
|
281
|
+
} else if s == "pending" {
|
|
282
|
+
Cell::new("Pending").fg(Color::Yellow)
|
|
283
|
+
} else {
|
|
284
|
+
Cell::new("Disabled").fg(Color::Red)
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
fn format_score_cell(score: u32) -> Cell {
|
|
289
|
+
let cell = Cell::new(score.to_string()).set_alignment(CellAlignment::Center);
|
|
290
|
+
if score >= 90 {
|
|
291
|
+
cell.fg(Color::Green).add_attribute(Attribute::Bold)
|
|
292
|
+
} else if score >= 80 {
|
|
293
|
+
cell.fg(Color::Green)
|
|
294
|
+
} else if score >= 70 {
|
|
295
|
+
cell.fg(Color::Yellow)
|
|
296
|
+
} else {
|
|
297
|
+
cell.fg(Color::Red).add_attribute(Attribute::Bold)
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
fn format_score_text(score: u32) -> ColoredString {
|
|
302
|
+
if score >= 90 {
|
|
303
|
+
format!("{}/100", score).bright_green().bold()
|
|
304
|
+
} else if score >= 80 {
|
|
305
|
+
format!("{}/100", score).green().bold()
|
|
306
|
+
} else if score >= 70 {
|
|
307
|
+
format!("{}/100", score).yellow().bold()
|
|
308
|
+
} else {
|
|
309
|
+
format!("{}/100", score).bright_red().bold()
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
fn format_grade_cell(grade: &str) -> Cell {
|
|
314
|
+
let cell = Cell::new(grade).set_alignment(CellAlignment::Center);
|
|
315
|
+
match grade {
|
|
316
|
+
"A+" | "A" => cell.fg(Color::Green).add_attribute(Attribute::Bold),
|
|
317
|
+
"B" => cell.fg(Color::Green),
|
|
318
|
+
"C" => cell.fg(Color::Yellow),
|
|
319
|
+
"D" => cell.fg(Color::Yellow).add_attribute(Attribute::Bold),
|
|
320
|
+
_ => cell.fg(Color::Red).add_attribute(Attribute::Bold),
|
|
321
|
+
}
|
|
322
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
use crate::zone::models::{RiskLevel, RuleCategory};
|
|
2
|
+
|
|
3
|
+
/// Metadata definition for a security audit rule
|
|
4
|
+
#[derive(Debug, Clone)]
|
|
5
|
+
pub struct RuleDefinition {
|
|
6
|
+
pub id: &'static str,
|
|
7
|
+
pub name: &'static str,
|
|
8
|
+
pub category: RuleCategory,
|
|
9
|
+
pub default_severity: RiskLevel,
|
|
10
|
+
pub title: &'static str,
|
|
11
|
+
pub description: &'static str,
|
|
12
|
+
pub remediation: &'static str,
|
|
13
|
+
pub doc_url: &'static str,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
pub const ALL_RULES: &[RuleDefinition] = &[
|
|
17
|
+
RuleDefinition {
|
|
18
|
+
id: "CF-SSL-001",
|
|
19
|
+
name: "SSLModeCheck",
|
|
20
|
+
category: RuleCategory::SslTls,
|
|
21
|
+
default_severity: RiskLevel::Critical,
|
|
22
|
+
title: "Insecure SSL/TLS Encryption Mode",
|
|
23
|
+
description: "SSL mode is set to 'off' or 'flexible'. Flexible SSL does not encrypt traffic between Cloudflare edge servers and origin servers, exposing sensitive payload data to Man-In-The-Middle (MITM) attacks.",
|
|
24
|
+
remediation: "Navigate to SSL/TLS > Overview in Cloudflare Dashboard and set SSL/TLS encryption mode to 'Full (strict)'. Ensure a valid SSL certificate is installed on the origin server.",
|
|
25
|
+
doc_url: "https://developers.cloudflare.com/ssl/origin-configuration/ssl-modes/full-strict/",
|
|
26
|
+
},
|
|
27
|
+
RuleDefinition {
|
|
28
|
+
id: "CF-SSL-002",
|
|
29
|
+
name: "SSLNotStrict",
|
|
30
|
+
category: RuleCategory::SslTls,
|
|
31
|
+
default_severity: RiskLevel::Medium,
|
|
32
|
+
title: "SSL/TLS Mode is Full (Non-Strict)",
|
|
33
|
+
description: "SSL mode is set to 'full' instead of 'full (strict)'. Full mode does not validate the origin certificate against a trusted CA, leaving the connection susceptible to origin spoofing.",
|
|
34
|
+
remediation: "Upgrade SSL/TLS mode to 'Full (strict)' after validating origin server certificates (Cloudflare Origin CA or public CA).",
|
|
35
|
+
doc_url: "https://developers.cloudflare.com/ssl/origin-configuration/ssl-modes/full-strict/",
|
|
36
|
+
},
|
|
37
|
+
RuleDefinition {
|
|
38
|
+
id: "CF-TLS-001",
|
|
39
|
+
name: "MinimumTlsVersion",
|
|
40
|
+
category: RuleCategory::SslTls,
|
|
41
|
+
default_severity: RiskLevel::High,
|
|
42
|
+
title: "Deprecated Minimum TLS Version (< 1.2)",
|
|
43
|
+
description: "Minimum TLS version is set below TLS 1.2 (e.g. TLS 1.0 or 1.1). Legacy TLS protocols contain known cryptographic weaknesses (POODLE, BEAST) and fail PCI-DSS compliance.",
|
|
44
|
+
remediation: "Go to SSL/TLS > Edge Certificates > Minimum TLS Version and select 'TLS 1.2' or 'TLS 1.3'.",
|
|
45
|
+
doc_url: "https://developers.cloudflare.com/ssl/edge-certificates/minimum-tls-version/",
|
|
46
|
+
},
|
|
47
|
+
RuleDefinition {
|
|
48
|
+
id: "CF-TLS-002",
|
|
49
|
+
name: "Tls13Disabled",
|
|
50
|
+
category: RuleCategory::SslTls,
|
|
51
|
+
default_severity: RiskLevel::Low,
|
|
52
|
+
title: "TLS 1.3 Protocol Disabled",
|
|
53
|
+
description: "TLS 1.3 is disabled. TLS 1.3 provides significant latency improvements (0-RTT/1-RTT handshakes) and modern AEAD cipher suites.",
|
|
54
|
+
remediation: "Enable TLS 1.3 under SSL/TLS > Edge Certificates > TLS 1.3 in the Cloudflare Dashboard.",
|
|
55
|
+
doc_url: "https://developers.cloudflare.com/ssl/edge-certificates/additional-options/tls-13/",
|
|
56
|
+
},
|
|
57
|
+
RuleDefinition {
|
|
58
|
+
id: "CF-HTTPS-001",
|
|
59
|
+
name: "AlwaysUseHttps",
|
|
60
|
+
category: RuleCategory::HttpsEnforcement,
|
|
61
|
+
default_severity: RiskLevel::High,
|
|
62
|
+
title: "Always Use HTTPS Disabled",
|
|
63
|
+
description: "Unencrypted HTTP requests are not automatically redirected to HTTPS, allowing plaintext HTTP communication if requested by clients.",
|
|
64
|
+
remediation: "Enable 'Always Use HTTPS' in SSL/TLS > Edge Certificates in Cloudflare Dashboard.",
|
|
65
|
+
doc_url: "https://developers.cloudflare.com/ssl/edge-certificates/additional-options/always-use-https/",
|
|
66
|
+
},
|
|
67
|
+
RuleDefinition {
|
|
68
|
+
id: "CF-HTTPS-002",
|
|
69
|
+
name: "AutomaticHttpsRewrites",
|
|
70
|
+
category: RuleCategory::HttpsEnforcement,
|
|
71
|
+
default_severity: RiskLevel::Medium,
|
|
72
|
+
title: "Automatic HTTPS Rewrites Disabled",
|
|
73
|
+
description: "Automatic HTTPS rewrites is disabled, which may cause mixed-content warnings when HTTP resources are embedded in secure HTTPS pages.",
|
|
74
|
+
remediation: "Enable 'Automatic HTTPS Rewrites' under SSL/TLS > Edge Certificates.",
|
|
75
|
+
doc_url: "https://developers.cloudflare.com/ssl/edge-certificates/additional-options/automatic-https-rewrites/",
|
|
76
|
+
},
|
|
77
|
+
RuleDefinition {
|
|
78
|
+
id: "CF-HSTS-001",
|
|
79
|
+
name: "HstsDisabled",
|
|
80
|
+
category: RuleCategory::Hsts,
|
|
81
|
+
default_severity: RiskLevel::High,
|
|
82
|
+
title: "HTTP Strict Transport Security (HSTS) Disabled",
|
|
83
|
+
description: "HSTS header is not enabled for the zone. Without HSTS, browsers may allow initial unencrypted HTTP connections susceptible to SSL stripping attacks.",
|
|
84
|
+
remediation: "Enable HSTS under SSL/TLS > Edge Certificates > HTTP Strict Transport Security (HSTS).",
|
|
85
|
+
doc_url: "https://developers.cloudflare.com/ssl/edge-certificates/additional-options/http-strict-transport-security/",
|
|
86
|
+
},
|
|
87
|
+
RuleDefinition {
|
|
88
|
+
id: "CF-HSTS-002",
|
|
89
|
+
name: "HstsMaxAgeTooShort",
|
|
90
|
+
category: RuleCategory::Hsts,
|
|
91
|
+
default_severity: RiskLevel::Medium,
|
|
92
|
+
title: "HSTS Max-Age Duration Too Short (< 6 Months)",
|
|
93
|
+
description: "HSTS max-age duration is less than 15,552,000 seconds (6 months). A short max-age duration fails modern security baselines and HSTS preload requirements (minimum 1 year / 31,536,000s).",
|
|
94
|
+
remediation: "Increase HSTS max-age to at least 6 months (15,552,000 seconds) or preferably 1 year (31,536,000 seconds) in HSTS settings.",
|
|
95
|
+
doc_url: "https://developers.cloudflare.com/ssl/edge-certificates/additional-options/http-strict-transport-security/",
|
|
96
|
+
},
|
|
97
|
+
RuleDefinition {
|
|
98
|
+
id: "CF-HSTS-003",
|
|
99
|
+
name: "HstsIncludeSubdomainsMissing",
|
|
100
|
+
category: RuleCategory::Hsts,
|
|
101
|
+
default_severity: RiskLevel::Medium,
|
|
102
|
+
title: "HSTS Include Subdomains Disabled",
|
|
103
|
+
description: "HSTS does not apply to all subdomains (includeSubDomains is false). Unprotected subdomains remain vulnerable to downgrade attacks.",
|
|
104
|
+
remediation: "Check 'Apply HSTS policy to subdomains (includeSubDomains)' in HSTS settings.",
|
|
105
|
+
doc_url: "https://developers.cloudflare.com/ssl/edge-certificates/additional-options/http-strict-transport-security/",
|
|
106
|
+
},
|
|
107
|
+
RuleDefinition {
|
|
108
|
+
id: "CF-HSTS-004",
|
|
109
|
+
name: "HstsPreloadDisabled",
|
|
110
|
+
category: RuleCategory::Hsts,
|
|
111
|
+
default_severity: RiskLevel::Low,
|
|
112
|
+
title: "HSTS Preload Directive Missing",
|
|
113
|
+
description: "HSTS preload directive is not enabled. Without preloading, first-time site visitors are not protected by browser-baked HSTS lists.",
|
|
114
|
+
remediation: "Enable 'Preload' in HSTS settings and submit the domain to hstspreload.org.",
|
|
115
|
+
doc_url: "https://hstspreload.org/",
|
|
116
|
+
},
|
|
117
|
+
RuleDefinition {
|
|
118
|
+
id: "CF-HSTS-005",
|
|
119
|
+
name: "HstsNoSniffMissing",
|
|
120
|
+
category: RuleCategory::Hsts,
|
|
121
|
+
default_severity: RiskLevel::Low,
|
|
122
|
+
title: "HSTS No-Sniff Header Disabled",
|
|
123
|
+
description: "X-Content-Type-Options: nosniff header is disabled in HSTS security header configuration.",
|
|
124
|
+
remediation: "Enable 'No-Sniff' in HSTS settings to prevent MIME type sniffing attacks.",
|
|
125
|
+
doc_url: "https://developers.cloudflare.com/ssl/edge-certificates/additional-options/http-strict-transport-security/",
|
|
126
|
+
},
|
|
127
|
+
RuleDefinition {
|
|
128
|
+
id: "CF-WAF-001",
|
|
129
|
+
name: "WafManagedRulesDisabled",
|
|
130
|
+
category: RuleCategory::WafSecurity,
|
|
131
|
+
default_severity: RiskLevel::High,
|
|
132
|
+
title: "WAF Managed Rulesets Inactive",
|
|
133
|
+
description: "Cloudflare Web Application Firewall (WAF) managed rules are disabled or not configured. The zone lacks automated zero-day protection against OWASP Top 10 vulnerabilities.",
|
|
134
|
+
remediation: "Enable Cloudflare Managed Ruleset and OWASP Core Ruleset under Security > WAF > Managed Rules.",
|
|
135
|
+
doc_url: "https://developers.cloudflare.com/waf/managed-rules/",
|
|
136
|
+
},
|
|
137
|
+
RuleDefinition {
|
|
138
|
+
id: "CF-BOT-001",
|
|
139
|
+
name: "BotFightModeDisabled",
|
|
140
|
+
category: RuleCategory::BotManagement,
|
|
141
|
+
default_severity: RiskLevel::Medium,
|
|
142
|
+
title: "Bot Fight Mode / Bot Protection Inactive",
|
|
143
|
+
description: "Bot Fight Mode or Super Bot Fight Mode is disabled. Automated credential stuffing, scrapers, and malicious bot traffic are not actively mitigated.",
|
|
144
|
+
remediation: "Enable 'Bot Fight Mode' under Security > Bots in the Cloudflare Dashboard.",
|
|
145
|
+
doc_url: "https://developers.cloudflare.com/bots/get-started/free/",
|
|
146
|
+
},
|
|
147
|
+
RuleDefinition {
|
|
148
|
+
id: "CF-RATE-001",
|
|
149
|
+
name: "RateLimitingNotConfigured",
|
|
150
|
+
category: RuleCategory::WafSecurity,
|
|
151
|
+
default_severity: RiskLevel::Low,
|
|
152
|
+
title: "No Rate Limiting Rules Configured",
|
|
153
|
+
description: "No rate limiting rules are configured for this zone. Critical endpoints (e.g. login, search, APIs) may be susceptible to brute force or Layer 7 DoS attacks.",
|
|
154
|
+
remediation: "Configure rate limiting rules for authentication, API, and sensitive endpoints under Security > WAF > Rate Limiting.",
|
|
155
|
+
doc_url: "https://developers.cloudflare.com/waf/rate-limiting-rules/",
|
|
156
|
+
},
|
|
157
|
+
RuleDefinition {
|
|
158
|
+
id: "CF-DNS-001",
|
|
159
|
+
name: "DnssecDisabled",
|
|
160
|
+
category: RuleCategory::Dnssec,
|
|
161
|
+
default_severity: RiskLevel::Medium,
|
|
162
|
+
title: "DNSSEC Not Enabled",
|
|
163
|
+
description: "DNSSEC (Domain Name System Security Extensions) is disabled or inactive. Domain resolution is susceptible to DNS cache poisoning and spoofing.",
|
|
164
|
+
remediation: "Enable DNSSEC under DNS > Settings > Enable DNSSEC and add the DS record to your domain registrar.",
|
|
165
|
+
doc_url: "https://developers.cloudflare.com/dns/dnssec/",
|
|
166
|
+
},
|
|
167
|
+
RuleDefinition {
|
|
168
|
+
id: "CF-SEC-001",
|
|
169
|
+
name: "PermissiveIpAccessRule",
|
|
170
|
+
category: RuleCategory::AccessControl,
|
|
171
|
+
default_severity: RiskLevel::Critical,
|
|
172
|
+
title: "Overly Permissive IP Access Rule (0.0.0.0/0 or Wildcard Whitelist)",
|
|
173
|
+
description: "An IP Access Rule or Firewall Rule is configured to allow or whitelist '0.0.0.0/0', '::/0', or wide subnets, effectively bypassing security controls globally.",
|
|
174
|
+
remediation: "Review Security > WAF > Tools > IP Access Rules and remove any broad allow/whitelist rules for 0.0.0.0/0 or excessive CIDR blocks.",
|
|
175
|
+
doc_url: "https://developers.cloudflare.com/waf/tools/ip-access-rules/",
|
|
176
|
+
},
|
|
177
|
+
RuleDefinition {
|
|
178
|
+
id: "CF-SEC-002",
|
|
179
|
+
name: "InsecureSecurityLevel",
|
|
180
|
+
category: RuleCategory::SecurityLevel,
|
|
181
|
+
default_severity: RiskLevel::High,
|
|
182
|
+
title: "Zone Security Level Set to Ineffective Setting ('Essentially Off' or 'Low')",
|
|
183
|
+
description: "Zone Security Level is set to 'Essentially Off' or 'Low', disabling IP reputation scoring and bot challenge protection.",
|
|
184
|
+
remediation: "Set Security Level to 'Medium' or 'High' under Security > Settings in Cloudflare Dashboard.",
|
|
185
|
+
doc_url: "https://developers.cloudflare.com/waf/reference/security-level/",
|
|
186
|
+
},
|
|
187
|
+
RuleDefinition {
|
|
188
|
+
id: "CF-SEC-003",
|
|
189
|
+
name: "BrowserIntegrityCheckDisabled",
|
|
190
|
+
category: RuleCategory::SecurityLevel,
|
|
191
|
+
default_severity: RiskLevel::Low,
|
|
192
|
+
title: "Browser Integrity Check Disabled",
|
|
193
|
+
description: "Browser Integrity Check is disabled. HTTP headers commonly used by spammers and threat actors will not be challenged.",
|
|
194
|
+
remediation: "Enable 'Browser Integrity Check' under Security > Settings in Cloudflare Dashboard.",
|
|
195
|
+
doc_url: "https://developers.cloudflare.com/waf/reference/browser-integrity-check/",
|
|
196
|
+
},
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
pub fn get_rule_by_id(id: &str) -> Option<&'static RuleDefinition> {
|
|
200
|
+
ALL_RULES.iter().find(|r| r.id == id)
|
|
201
|
+
}
|