pub mod common;
pub mod cross_file;
pub mod csharp;
pub mod go;
pub mod go_taint;
pub mod java;
pub mod javascript;
pub mod javascript_taint;
pub mod kotlin;
pub mod php;
pub mod python;
pub mod python_aliases;
pub mod python_taint;
pub mod ruby;
pub mod rust_lang;
pub mod semgrep_compat;
pub mod semgrep_taint;
pub mod swift;
use crate::{Finding, Language, Severity};
use std::path::Path;
#[macro_export]
macro_rules! impl_rule {
(
$struct:ty,
id = $id:expr,
severity = $sev:expr,
cwe = $cwe:expr,
description = $desc:expr,
language = $lang:expr,
fn check($self_:ident, $src:ident, $tree:ident) { $($check_body:tt)* }
) => {
impl $crate::rules::Rule for $struct {
fn id(&self) -> &str { $id }
fn severity(&self) -> $crate::Severity { $sev }
fn cwe(&self) -> Option<&str> { $cwe }
fn description(&self) -> &str { $desc }
fn language(&self) -> $crate::Language { $lang }
fn check(&self, $src: &str, $tree: &tree_sitter::Tree) -> Vec<$crate::Finding> {
let $self_ = self;
$($check_body)*
}
}
};
(
$struct:ty,
id = $id:expr,
severity = $sev:expr,
cwe = $cwe:expr,
description = $desc:expr,
language = $lang:expr,
fn check_with_context($self_:ident, $src:ident, $tree:ident, $ctx:ident) { $($check_body:tt)* }
) => {
impl $crate::rules::Rule for $struct {
fn id(&self) -> &str { $id }
fn severity(&self) -> $crate::Severity { $sev }
fn cwe(&self) -> Option<&str> { $cwe }
fn description(&self) -> &str { $desc }
fn language(&self) -> $crate::Language { $lang }
fn check(&self, source: &str, tree: &tree_sitter::Tree) -> Vec<$crate::Finding> {
self.check_with_context(source, tree, &$crate::rules::FileContext::default())
}
fn check_with_context(
&self,
$src: &str,
$tree: &tree_sitter::Tree,
$ctx: &$crate::rules::FileContext<'_>,
) -> Vec<$crate::Finding> {
let $self_ = self;
$($check_body)*
}
}
};
}
#[derive(Default)]
pub struct FileContext<'a> {
pub python_aliases: Option<&'a common::AliasTable>,
pub javascript_aliases: Option<&'a common::AliasTable>,
pub go_aliases: Option<&'a common::AliasTable>,
pub cross_file_summaries: Option<&'a cross_file::CrossFileSummaryMap>,
pub python_import_paths: Option<&'a std::collections::HashMap<String, std::path::PathBuf>>,
pub javascript_import_paths: Option<&'a std::collections::HashMap<String, std::path::PathBuf>>,
pub go_same_package_paths: Option<Vec<std::path::PathBuf>>,
}
pub trait Rule: Send + Sync {
fn id(&self) -> &str;
fn severity(&self) -> Severity;
fn cwe(&self) -> Option<&str>;
fn description(&self) -> &str;
fn language(&self) -> Language;
fn applies_to_path(&self, _path: &Path) -> bool {
true
}
fn check(&self, source: &str, tree: &tree_sitter::Tree) -> Vec<Finding>;
fn check_with_context(
&self,
source: &str,
tree: &tree_sitter::Tree,
_ctx: &FileContext<'_>,
) -> Vec<Finding> {
self.check(source, tree)
}
}
pub struct RuleRegistry {
rules: Vec<Box<dyn Rule>>,
}
impl Default for RuleRegistry {
fn default() -> Self {
Self::new()
}
}
impl RuleRegistry {
pub fn empty() -> Self {
Self { rules: Vec::new() }
}
pub fn new() -> Self {
let mut registry = Self { rules: Vec::new() };
registry.register(Box::new(javascript::NoEval));
registry.register(Box::new(javascript::NoHardcodedSecret));
registry.register(Box::new(javascript::NoSqlInjection));
registry.register(Box::new(javascript::NoXssInnerHtml));
registry.register(Box::new(javascript::NoCommandInjection));
registry.register(Box::new(javascript::NoDocumentWrite));
registry.register(Box::new(javascript::NoOpenRedirect));
registry.register(Box::new(javascript::NoWeakCrypto));
registry.register(Box::new(javascript::NoPathTraversal));
registry.register(Box::new(javascript::NoSsrf));
registry.register(Box::new(javascript::NoPrototypePollution));
registry.register(Box::new(javascript::NoUnsafeRegex));
registry.register(Box::new(javascript::NoCorsStar));
registry.register(Box::new(javascript::ExpressNoHardcodedSessionSecret));
registry.register(Box::new(javascript::ExpressCookieNoSecure));
registry.register(Box::new(javascript::ExpressCookieNoHttpOnly));
registry.register(Box::new(javascript::ExpressCookieNoSameSite));
registry.register(Box::new(javascript::ExpressSessionSaveUninitializedTrue));
registry.register(Box::new(javascript::ExpressSessionResaveTrue));
registry.register(Box::new(javascript::ExpressDirectResponseWrite));
registry.register(Box::new(javascript::JwtHardcodedSecret));
registry.register(Box::new(javascript::JwtNoneAlgorithm));
registry.register(Box::new(javascript::JwtIgnoreExpiration));
registry.register(Box::new(javascript::JwtDecodeWithoutVerify));
registry.register(Box::new(javascript::JwtVerifyMissingAlgorithms));
registry.register(Box::new(javascript::NoUnsafeFormatString));
registry.register(Box::new(javascript::TaintXssInnerHtml));
registry.register(Box::new(javascript::TaintSqlInjection));
registry.register(Box::new(javascript::TaintEval));
registry.register(Box::new(javascript::TaintCommandInjection));
registry.register(Box::new(javascript::TaintSsrf));
registry.register(Box::new(javascript::TaintSsti));
registry.register(Box::new(javascript::TaintXpathInjection));
registry.register(Box::new(javascript::TaintLdapInjection));
registry.register(Box::new(javascript::TaintLogInjection));
registry.register(Box::new(javascript::TaintXxe));
registry.register(Box::new(javascript::NoUnsafeDeserialization));
registry.register(Box::new(javascript::TaintNosqlInjection));
registry.register(Box::new(python::NoEval));
registry.register(Box::new(python::NoHardcodedSecret));
registry.register(Box::new(python::NoSqlInjection));
registry.register(Box::new(python::NoCommandInjection));
registry.register(Box::new(python::NoPathTraversal));
registry.register(Box::new(python::NoSsrf));
registry.register(Box::new(python::NoWeakCrypto));
registry.register(Box::new(python::NoPickle));
registry.register(Box::new(python::NoYamlLoad));
registry.register(Box::new(python::NoDebugTrue));
registry.register(Box::new(python::NoOpenRedirect));
registry.register(Box::new(python::NoCorsStar));
registry.register(Box::new(python::FlaskDebugMode));
registry.register(Box::new(python::DjangoSecretKeyHardcoded));
registry.register(Box::new(python::FlaskSecretKeyHardcoded));
registry.register(Box::new(python::SessionCookieSecureDisabled));
registry.register(Box::new(python::SessionCookieHttpOnlyDisabled));
registry.register(Box::new(python::SessionCookieSameSiteDisabled));
registry.register(Box::new(python::CsrfCookieSecureDisabled));
registry.register(Box::new(python::CsrfCookieHttpOnlyDisabled));
registry.register(Box::new(python::CsrfCookieSameSiteDisabled));
registry.register(Box::new(python::CsrfExempt));
registry.register(Box::new(python::WtfCsrfDisabled));
registry.register(Box::new(python::WtfCsrfCheckDefaultDisabled));
registry.register(Box::new(python::DjangoAllowedHostsWildcard));
registry.register(Box::new(python::SecureSslRedirectDisabled));
registry.register(Box::new(python::TaintPickleDeserialization));
registry.register(Box::new(python::TaintEvalFromRequest));
registry.register(Box::new(python::TaintCommandInjectionFromRequest));
registry.register(Box::new(python::TaintSsrfFromRequest));
registry.register(Box::new(python::TaintYamlLoadFromRequest));
registry.register(Box::new(python::TaintSqlInjectionFromRequest));
registry.register(Box::new(python::TaintSsti));
registry.register(Box::new(python::TaintXpathInjection));
registry.register(Box::new(python::TaintLdapInjection));
registry.register(Box::new(python::TaintLogInjection));
registry.register(Box::new(python::TaintXxe));
registry.register(Box::new(python::JwtNoVerify));
registry.register(Box::new(python::JwtHardcodedSecret));
registry.register(Box::new(python::TaintNosqlInjection));
registry.register(Box::new(go::NoSqlInjection));
registry.register(Box::new(go::NoCommandInjection));
registry.register(Box::new(go::NoHardcodedSecret));
registry.register(Box::new(go::NoWeakCrypto));
registry.register(Box::new(go::NoSsrf));
registry.register(Box::new(go::InsecureTlsSkipVerify));
registry.register(Box::new(go::GinNoTrustedProxies));
registry.register(Box::new(go::NetHttpNoTimeout));
registry.register(Box::new(go::TaintCommandInjection));
registry.register(Box::new(go::TaintSqlInjection));
registry.register(Box::new(go::TaintSsrf));
registry.register(Box::new(go::TaintSsti));
registry.register(Box::new(go::TaintXpathInjection));
registry.register(Box::new(go::TaintLdapInjection));
registry.register(Box::new(go::TaintLogInjection));
registry.register(Box::new(go::NoUnsafeDeserialization));
registry.register(Box::new(go::JwtNoVerify));
registry.register(Box::new(go::JwtHardcodedSecret));
registry.register(Box::new(go::TaintNosqlInjection));
registry.register(Box::new(go::TaintPathTraversal));
registry.register(Box::new(java::NoSqlInjection));
registry.register(Box::new(java::NoCommandInjection));
registry.register(Box::new(java::NoUnsafeDeserialization));
registry.register(Box::new(java::NoSsrf));
registry.register(Box::new(java::NoPathTraversal));
registry.register(Box::new(java::NoWeakCrypto));
registry.register(Box::new(java::NoHardcodedSecret));
registry.register(Box::new(java::NoXxe));
registry.register(Box::new(java::SpringCsrfDisabled));
registry.register(Box::new(java::SpringCorsPermissive));
registry.register(Box::new(java::NoXss));
registry.register(Box::new(php::NoEval));
registry.register(Box::new(php::NoCommandInjection));
registry.register(Box::new(php::NoSqlInjection));
registry.register(Box::new(php::NoUnserialize));
registry.register(Box::new(php::NoFileInclusion));
registry.register(Box::new(php::NoWeakCrypto));
registry.register(Box::new(php::NoHardcodedSecret));
registry.register(Box::new(php::NoSsrf));
registry.register(Box::new(php::NoExtract));
registry.register(Box::new(php::NoPregEval));
registry.register(Box::new(ruby::NoEval));
registry.register(Box::new(ruby::NoCommandInjection));
registry.register(Box::new(ruby::NoSqlInjection));
registry.register(Box::new(ruby::NoMassAssignment));
registry.register(Box::new(ruby::NoUnsafeDeserialization));
registry.register(Box::new(ruby::NoOpenRedirect));
registry.register(Box::new(ruby::NoCsrfSkip));
registry.register(Box::new(ruby::NoHtmlSafe));
registry.register(Box::new(ruby::NoHardcodedSecret));
registry.register(Box::new(ruby::NoWeakCrypto));
registry.register(Box::new(ruby::NoSsrf));
registry.register(Box::new(ruby::NoPathTraversal));
registry.register(Box::new(csharp::NoSqlInjection));
registry.register(Box::new(csharp::NoCommandInjection));
registry.register(Box::new(csharp::NoUnsafeDeserialization));
registry.register(Box::new(csharp::NoSsrf));
registry.register(Box::new(csharp::NoPathTraversal));
registry.register(Box::new(csharp::NoWeakCrypto));
registry.register(Box::new(csharp::NoHardcodedSecret));
registry.register(Box::new(csharp::NoXxe));
registry.register(Box::new(csharp::NoLdapInjection));
registry.register(Box::new(csharp::NoCorsStar));
registry.register(Box::new(swift::NoHardcodedSecret));
registry.register(Box::new(swift::NoCommandInjection));
registry.register(Box::new(swift::NoWeakCrypto));
registry.register(Box::new(swift::NoInsecureTransport));
registry.register(Box::new(swift::NoEvalJs));
registry.register(Box::new(swift::NoSqlInjection));
registry.register(Box::new(swift::NoInsecureKeychain));
registry.register(Box::new(swift::NoTlsDisabled));
registry.register(Box::new(swift::NoPathTraversal));
registry.register(Box::new(swift::NoSsrf));
registry.register(Box::new(kotlin::NoSqlInjection));
registry.register(Box::new(kotlin::NoCommandInjection));
registry.register(Box::new(kotlin::NoUnsafeDeserialization));
registry.register(Box::new(kotlin::NoSsrf));
registry.register(Box::new(kotlin::NoPathTraversal));
registry.register(Box::new(kotlin::NoWeakCrypto));
registry.register(Box::new(kotlin::NoHardcodedSecret));
registry.register(Box::new(kotlin::NoXxe));
registry.register(Box::new(kotlin::NoCorsStar));
registry.register(Box::new(kotlin::NoEval));
registry.register(Box::new(kotlin::TaintSqlInjection));
registry.register(Box::new(kotlin::TaintCommandInjection));
registry.register(Box::new(kotlin::TaintSsrf));
registry.register(Box::new(rust_lang::UnsafeBlock));
registry.register(Box::new(rust_lang::TransmuteUsage));
registry.register(Box::new(rust_lang::NoCommandInjection));
registry.register(Box::new(rust_lang::NoSqlInjection));
registry.register(Box::new(rust_lang::NoWeakHash));
registry.register(Box::new(rust_lang::NoHardcodedSecret));
registry.register(Box::new(rust_lang::TlsVerifyDisabled));
registry.register(Box::new(rust_lang::NoSsrf));
registry.register(Box::new(rust_lang::NoPathTraversal));
registry.register(Box::new(rust_lang::NoUnwrapInLib));
registry
}
pub fn register(&mut self, rule: Box<dyn Rule>) {
self.rules.push(rule);
}
pub fn rules_for_language(&self, language: Language) -> Vec<&dyn Rule> {
self.rules
.iter()
.filter(|r| r.language() == language)
.map(|r| r.as_ref())
.collect()
}
#[allow(dead_code)]
pub fn all_rules(&self) -> &[Box<dyn Rule>] {
&self.rules
}
}