secfinding 0.1.1

Universal security finding types — Severity, Evidence, Finding, FindingKind
Documentation

secfinding — Shared security finding model

License Tests Crates.io

Why

Security tooling only scales when every scanner outputs the same structured finding schema. secfinding is that schema for the Santh ecosystem: severity, type, evidence, location, and metadata in one canonical shape.

This crate removes duplicated model code and lets reporting, aggregation, and downstream integrations work with one contract regardless of whether findings came from web scans, code scanners, or payload engines.

Quick Start

use secfinding::{Finding, FindingKind, Evidence, Severity};

fn main() {
    let finding = Finding::builder("php-taint", "https://example.com", Severity::Critical)
        .title("Command execution from user input")
        .detail("eval receives unsanitized data from GET")
        .kind(FindingKind::Vulnerability)
        .evidence(Evidence::code("src/index.php", 12, "$cmd = $_GET['cmd']"))
        .tag("rce")
        .confidence(0.95)
        .exploit_hint("curl -d 'cmd=id' https://example.com/index.php")
        .build();

    println!("{} => {}", finding.target, finding.title);
}

Features

  • Canonical Finding struct for cross-tool exchange.
  • Severity and finding classification via Severity and FindingKind.
  • Rich, typed evidence in Evidence (HTTP, DNS, snippets, certificates, patterns).
  • Fluent FindingBuilder plus Finding::new convenience constructor.
  • Default Reportable implementation for rendering pipelines.

TOML Configuration

Use [FindingFilter::from_toml] to configure severity/scanner/tag filtering.

min_severity = "high"
exclude_scanners = ["nmap"]
include_tags = ["sqli", "rce"]
use secfinding::{filter, Finding, FindingFilter};

let cfg = FindingFilter::from_toml(r#"
min_severity = \"high\"
exclude_scanners = [\"gobuster\"]
include_tags = [\"rce\"]
"#).unwrap();

let filtered: Vec<Finding> = filter(&findings, &cfg);

API Overview

  • Finding, FindingBuilder: main payload and fluent constructor API.
  • FindingKind: vulnerability/misconfig/exposure/secret/etc.
  • Severity: Info → Critical.
  • Evidence: structured proof payloads.
  • Reportable: trait consumed by secreport and compatible reporting crates.

Examples

1) Build a vulnerability finding with typed evidence

use secfinding::{Finding, Evidence, FindingKind, Severity};

let finding = Finding::builder("sast", "src/user.rs", Severity::High)
    .title("Hardcoded secret")
    .detail("API key loaded from source code")
    .kind(FindingKind::SecretLeak)
    .evidence(Evidence::code("src/user.rs", 42, "let api_key = \"AKIA...\";"))
    .tag("secrets")
    .cve("CWE-798")
    .build();

2) Classify findings by type

use secfinding::FindingKind;

let kind = FindingKind::Misconfiguration;
println!("{} actionable: {}", kind, kind.is_actionable());

3) Render a multi-tool finding list with secfinding types

use secfinding::{Finding, FindingKind, Severity};

let mut findings = vec![
    Finding::new("web", "https://example.com", Severity::Low, "Weak CSP", "Content-Security-Policy missing"),
];

findings[0].kind = FindingKind::Misconfiguration;
println!("{} finding(s)", findings.len());

Traits

secfinding defines Reportable to decouple finding models from rendering implementations.

use secfinding::{Reportable, Severity};

struct CustomFinding {
    target: String,
}

impl Reportable for CustomFinding {
    fn scanner(&self) -> &str { "custom-scanner" }
    fn target(&self) -> &str { &self.target }
    fn severity(&self) -> Severity { Severity::Medium }
    fn title(&self) -> &str { "Custom signal" }
}

Related Crates

License

MIT, Corum Collective LLC

Docs: https://docs.rs/secfinding

Santh ecosystem: https://santh.io