forked from mirrors/kingfisher
Fixed broken pagerduty rule
This commit is contained in:
parent
9b5c220182
commit
e7e391ab98
8 changed files with 50 additions and 46 deletions
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [1.13.1]
|
||||
- Fixed broken pagerduty rule
|
||||
|
||||
## [1.13.0]
|
||||
- Added new rules for Planetscale, Postman, Openweather, opsgenie, pagerduty, pastebin, paypal, netlify, netrc, newrelic, ngrok, npm, nuget, mandrill, mapbox, microsoft teams, stripe, linkedin, mailchimp, mailgun, linear, line, huggingface, ibm cloud, intercom, ipstack, heroku, gradle, grafana
|
||||
- Added `--rule-stats` command-line flag that will display rule performance statistics during a scan. Useful when creating or debugging rules
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ publish = false
|
|||
|
||||
[package]
|
||||
name = "kingfisher"
|
||||
version = "1.13.0"
|
||||
version = "1.13.1"
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
|||
|
|
@ -2,35 +2,46 @@ rules:
|
|||
- name: PagerDuty API Key
|
||||
id: kingfisher.pagerduty.1
|
||||
pattern: |
|
||||
(?xi)
|
||||
(?xi)
|
||||
\b
|
||||
(?:pagerduty|pager[_-]duty|pd[-_\]=\)]|pd\.webhook?)
|
||||
(?:.|[\n\r]){0,16}?
|
||||
(
|
||||
u\+[A-Z0-9_+-]{18} # new personal tokens
|
||||
|
|
||||
[A-Z0-9_-]{20} # legacy personal tokens
|
||||
|
|
||||
[A-F0-9]{32} # integration keys / routing keys
|
||||
(?:
|
||||
Token |
|
||||
Authorization |
|
||||
pd[_-]? |
|
||||
pd[_-]? |
|
||||
pagerduty[_-]? |
|
||||
pagerduty
|
||||
)
|
||||
\b
|
||||
min_entropy: 3.3
|
||||
(?:.|[\n\r]){0,16}?
|
||||
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
|
||||
(?:.|[\n\r]){0,16}?
|
||||
(
|
||||
u\+[A-Z0-9_+-]{18} | # personal user token (20 chars)
|
||||
[A-Z0-9_-]{20} | # legacy PAT (20 chars, mixed case)
|
||||
[a-f0-9]{32} # integration / routing key (32 hex, lower case)
|
||||
)
|
||||
\b
|
||||
min_entropy: 3.5
|
||||
confidence: medium
|
||||
examples:
|
||||
- pagerduty_key = u+Lyhd2_N2MCy+ZoH-S5
|
||||
- "Authorization: Token token=u+Lyhd2_N2MCy+ZoH-S5"
|
||||
- pd_key = u+3xVszZ-b4m+T6d23KA
|
||||
- Token token=ABCDEF1234567890ABCDEF1234567890
|
||||
references:
|
||||
- https://developer.pagerduty.com/api-reference/c96e889522dd6-list-users
|
||||
validation:
|
||||
type: Http
|
||||
content:
|
||||
request:
|
||||
method: GET
|
||||
url: https://api.pagerduty.com/abilities
|
||||
url: https://api.pagerduty.com/users
|
||||
headers:
|
||||
Authorization: Token token={{ TOKEN }}
|
||||
Accept: application/vnd.pagerduty+json;version=2
|
||||
Content-Type: application/json
|
||||
response_matcher:
|
||||
- report_response: true
|
||||
- type: StatusMatch
|
||||
status: [200]
|
||||
- type: WordMatch
|
||||
words: ['"abilities":']
|
||||
status: [200]
|
||||
- type: WordMatch
|
||||
words: ['"user":']
|
||||
|
|
|
|||
|
|
@ -382,16 +382,11 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// 3) Nested archive:
|
||||
/// outer.tar.gz ──▶ outer.tar (contains inner.tar.gz)
|
||||
/// └──▶ inner.tar.gz ──▶ inner.tar (contains secret.txt)
|
||||
/// 3) Nested archive: outer.tar.gz ──▶ outer.tar (contains inner.tar.gz) └──▶ inner.tar.gz
|
||||
/// ──▶ inner.tar (contains secret.txt)
|
||||
#[test]
|
||||
fn smoke_decompress_nested_tar_gz_archives() -> anyhow::Result<()> {
|
||||
use std::{
|
||||
fs::File,
|
||||
io::Read,
|
||||
path::PathBuf,
|
||||
};
|
||||
use std::{fs::File, io::Read, path::PathBuf};
|
||||
|
||||
use flate2::{write::GzEncoder, Compression};
|
||||
use tar::Builder;
|
||||
|
|
@ -468,10 +463,7 @@ mod tests {
|
|||
for (logical, path) in files {
|
||||
if logical.ends_with("!secret.txt") {
|
||||
let txt = std::fs::read_to_string(&path)?;
|
||||
assert!(
|
||||
txt.contains("nested_secret=shh"),
|
||||
"secret.txt content corrupted"
|
||||
);
|
||||
assert!(txt.contains("nested_secret=shh"), "secret.txt content corrupted");
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ use smallvec::SmallVec;
|
|||
use tracing::debug;
|
||||
use xxhash_rust::xxh3::xxh3_64;
|
||||
|
||||
use crate::rule_profiling::RuleTimer;
|
||||
use crate::{
|
||||
blob::{Blob, BlobId, BlobIdMap},
|
||||
entropy::calculate_shannon_entropy,
|
||||
|
|
@ -33,7 +32,7 @@ use crate::{
|
|||
origin::OriginSet,
|
||||
parser,
|
||||
parser::{Checker, Language},
|
||||
rule_profiling::{ConcurrentRuleProfiler, RuleStats},
|
||||
rule_profiling::{ConcurrentRuleProfiler, RuleStats, RuleTimer},
|
||||
rules::rule::Rule,
|
||||
rules_database::RulesDatabase,
|
||||
safe_list::is_safe_match,
|
||||
|
|
@ -464,15 +463,8 @@ fn filter_match<'b>(
|
|||
filename: &str,
|
||||
profiler: Option<&Arc<ConcurrentRuleProfiler>>,
|
||||
) {
|
||||
let mut timer = profiler.map(|p| {
|
||||
RuleTimer::new(
|
||||
p,
|
||||
rule.id(),
|
||||
rule.name(),
|
||||
&rule.syntax.pattern,
|
||||
filename,
|
||||
)
|
||||
});
|
||||
let mut timer =
|
||||
profiler.map(|p| RuleTimer::new(p, rule.id(), rule.name(), &rule.syntax.pattern, filename));
|
||||
|
||||
let initial_len = matches.len();
|
||||
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ pub fn print_scan_summary(
|
|||
if !stats.is_empty() {
|
||||
// Calculate dynamic column widths
|
||||
let name_w = stats.iter().map(|s| s.rule_name.len()).max().unwrap_or(4);
|
||||
let id_w = stats.iter().map(|s| s.rule_id.len()).max().unwrap_or(2);
|
||||
let id_w = stats.iter().map(|s| s.rule_id.len()).max().unwrap_or(2);
|
||||
|
||||
// Header
|
||||
safe_println!("\n{:-^1$}", " Rule Performance Stats ", name_w + id_w + 47);
|
||||
|
|
@ -173,7 +173,7 @@ pub fn print_scan_summary(
|
|||
"Slowest",
|
||||
"Average",
|
||||
name_w = name_w,
|
||||
id_w = id_w
|
||||
id_w = id_w
|
||||
);
|
||||
safe_println!("{:-<width$}", "", width = name_w + id_w + 49);
|
||||
|
||||
|
|
@ -187,14 +187,13 @@ pub fn print_scan_summary(
|
|||
rs.slowest_match_time,
|
||||
rs.average_match_time,
|
||||
name_w = name_w,
|
||||
id_w = id_w
|
||||
id_w = id_w
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
debug!("\nAll Rules with Matches:");
|
||||
debug!("=======================");
|
||||
let max_rule_length = sorted_findings.iter().map(|(rule, _)| rule.len()).max().unwrap_or(0);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ fn scan_fails_for_bad_rule_yaml() {
|
|||
"--rules-path",
|
||||
tmp.path().to_str().unwrap(), // point loader at bad YAML
|
||||
"--no-validate", // keep the test fast
|
||||
"--no-update-check", // skip update check to avoid network calls
|
||||
"--no-update-check", // skip update check to avoid network calls
|
||||
])
|
||||
.assert()
|
||||
.failure()
|
||||
|
|
@ -72,7 +72,7 @@ rules:
|
|||
tmp.path().to_str().unwrap(), // only the custom rule
|
||||
"--no-dedup",
|
||||
"--load-builtins=false", // skip the builtin rules
|
||||
"--no-update-check", // skip update check to avoid network calls
|
||||
"--no-update-check", // skip update check to avoid network calls
|
||||
])
|
||||
.assert()
|
||||
.failure() // CLI exits 0
|
||||
|
|
|
|||
|
|
@ -30,7 +30,14 @@ fn smoke_scan_tar_gz_archive() -> anyhow::Result<()> {
|
|||
|
||||
// ── 1) extraction ENABLED -- secret should be found ─────────────────────────
|
||||
Command::cargo_bin("kingfisher")?
|
||||
.args(["scan", tar_gz.to_str().unwrap(), "--confidence=low", "--format", "json", "--no-update-check"])
|
||||
.args([
|
||||
"scan",
|
||||
tar_gz.to_str().unwrap(),
|
||||
"--confidence=low",
|
||||
"--format",
|
||||
"json",
|
||||
"--no-update-check",
|
||||
])
|
||||
.assert()
|
||||
.code(findings_code)
|
||||
.stdout(predicates::str::contains(github_pat));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue