diff --git a/detect/detect_test.go b/detect/detect_test.go index 260412d..2c96c67 100644 --- a/detect/detect_test.go +++ b/detect/detect_test.go @@ -245,6 +245,10 @@ func TestPythonProject(t *testing.T) { assertToolDetected(t, r, "lint", "Ruff") assertToolDetected(t, r, "typecheck", "mypy") + // Detection-only library defs via dependencies primitive + assertToolDetected(t, r, "build", "requests") + assertToolDetected(t, r, "build", "Jinja2") + // Layout if r.Layout == nil { t.Fatal("expected layout info") diff --git a/detect/threat_test.go b/detect/threat_test.go index a6c3f52..ad33bea 100644 --- a/detect/threat_test.go +++ b/detect/threat_test.go @@ -248,6 +248,40 @@ func TestThreatModelGoProjectEmpty(t *testing.T) { } } +func TestThreatModelPythonLibs(t *testing.T) { + // Python fixture has requests (function:http-client) and jinja2 + // (function:templating) which fire SSRF and XSS/SSTI mappings. + engine := New(loadKB(t), "../testdata/python-project") + r, err := engine.Run() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + tr := engine.ThreatModel(r) + threatIDs := make(map[string][]string) + for _, th := range tr.Threats { + threatIDs[th.ID] = th.IntroducedBy + } + + if intro, ok := threatIDs["ssrf"]; !ok { + t.Error("expected ssrf threat from requests") + } else if !slices.Contains(intro, "requests") { + t.Errorf("ssrf introduced_by = %v, want to include requests", intro) + } + + if intro, ok := threatIDs["ssti"]; !ok { + t.Error("expected ssti threat from jinja2") + } else if !slices.Contains(intro, "Jinja2") { + t.Errorf("ssti introduced_by = %v, want to include Jinja2", intro) + } + + if intro, ok := threatIDs["xss"]; !ok { + t.Error("expected xss threat from jinja2 templating") + } else if !slices.Contains(intro, "Jinja2") { + t.Errorf("xss introduced_by = %v, want to include Jinja2", intro) + } +} + func TestSinksRubyProject(t *testing.T) { engine := New(loadKB(t), "../testdata/ruby-project") r, err := engine.Run() diff --git a/knowledge/csharp/newtonsoft-json.toml b/knowledge/csharp/newtonsoft-json.toml new file mode 100644 index 0000000..096c9d7 --- /dev/null +++ b/knowledge/csharp/newtonsoft-json.toml @@ -0,0 +1,28 @@ +[tool] +name = "Newtonsoft.Json" +category = "build" +homepage = "https://www.newtonsoft.com/json" +docs = "https://www.newtonsoft.com/json" +repo = "https://github.com/JamesNK/Newtonsoft.Json" +description = "JSON framework for .NET" + +[detect] +dependencies = ["Newtonsoft.Json"] +ecosystems = ["csharp"] + +[taxonomy] +role = ["library"] +function = ["serialization", "parsing"] +layer = ["backend"] + +[[security.sinks]] +symbol = "TypeNameHandling" +threat = "deserialization" +cwe = "CWE-502" +note = "TypeNameHandling.All or .Auto enables polymorphic gadgets" + +[[security.sinks]] +symbol = "JsonConvert.DeserializeObject" +threat = "deserialization" +cwe = "CWE-502" +note = "When TypeNameHandling is enabled" diff --git a/knowledge/go/golang-jwt.toml b/knowledge/go/golang-jwt.toml new file mode 100644 index 0000000..989a38c --- /dev/null +++ b/knowledge/go/golang-jwt.toml @@ -0,0 +1,27 @@ +[tool] +name = "golang-jwt" +category = "build" +homepage = "https://golang-jwt.github.io/jwt" +docs = "https://golang-jwt.github.io/jwt" +repo = "https://github.com/golang-jwt/jwt" +description = "JWT implementation for Go" + +[detect] +dependencies = ["github.com/golang-jwt/jwt/v5", "github.com/golang-jwt/jwt/v4", "github.com/golang-jwt/jwt"] +ecosystems = ["go"] + +[taxonomy] +role = ["library"] +function = ["authentication"] +layer = ["backend"] + +[[security.sinks]] +symbol = "jwt.Parse" +threat = "auth_bypass" +cwe = "CWE-347" +note = "Keyfunc must verify token.Method against expected" + +[[security.sinks]] +symbol = "jwt.ParseWithClaims" +threat = "auth_bypass" +cwe = "CWE-347" diff --git a/knowledge/go/resty.toml b/knowledge/go/resty.toml new file mode 100644 index 0000000..91cf212 --- /dev/null +++ b/knowledge/go/resty.toml @@ -0,0 +1,32 @@ +[tool] +name = "Resty" +category = "build" +homepage = "https://resty.dev" +docs = "https://resty.dev" +repo = "https://github.com/go-resty/resty" +description = "HTTP and REST client for Go" + +[detect] +dependencies = ["github.com/go-resty/resty/v2", "github.com/go-resty/resty"] +ecosystems = ["go"] + +[taxonomy] +role = ["library"] +function = ["http-client"] +layer = ["backend"] + +[[security.sinks]] +symbol = "client.R().Get" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "client.R().Post" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "SetHostURL" +threat = "ssrf" +cwe = "CWE-918" +note = "When base URL is caller-controlled" diff --git a/knowledge/java/freemarker.toml b/knowledge/java/freemarker.toml new file mode 100644 index 0000000..8a4c56d --- /dev/null +++ b/knowledge/java/freemarker.toml @@ -0,0 +1,28 @@ +[tool] +name = "FreeMarker" +category = "build" +homepage = "https://freemarker.apache.org" +docs = "https://freemarker.apache.org" +repo = "https://github.com/apache/freemarker" +description = "Template engine for Java" + +[detect] +dependencies = ["org.freemarker:freemarker"] +ecosystems = ["java"] + +[taxonomy] +role = ["library"] +function = ["templating"] +layer = ["backend"] + +[[security.sinks]] +symbol = "?no_esc" +threat = "xss" +cwe = "CWE-79" +note = "Built-in that bypasses autoescaping" + +[[security.sinks]] +symbol = "Template.process" +threat = "ssti" +cwe = "CWE-1336" +note = "When template source is caller-controlled; new() built-in" diff --git a/knowledge/java/gson.toml b/knowledge/java/gson.toml new file mode 100644 index 0000000..064ee62 --- /dev/null +++ b/knowledge/java/gson.toml @@ -0,0 +1,22 @@ +[tool] +name = "Gson" +category = "build" +homepage = "https://github.com/google/gson" +docs = "https://github.com/google/gson" +repo = "https://github.com/google/gson" +description = "JSON serialization for Java" + +[detect] +dependencies = ["com.google.code.gson:gson"] +ecosystems = ["java"] + +[taxonomy] +role = ["library"] +function = ["serialization", "parsing"] +layer = ["backend"] + +[[security.sinks]] +symbol = "fromJson" +threat = "deserialization" +cwe = "CWE-502" +note = "Less gadget surface than Jackson but still risk with custom adapters" diff --git a/knowledge/java/jackson.toml b/knowledge/java/jackson.toml new file mode 100644 index 0000000..259eafc --- /dev/null +++ b/knowledge/java/jackson.toml @@ -0,0 +1,34 @@ +[tool] +name = "Jackson" +category = "build" +homepage = "https://github.com/FasterXML/jackson" +docs = "https://github.com/FasterXML/jackson" +repo = "https://github.com/FasterXML/jackson-databind" +description = "JSON processor for Java" + +[detect] +dependencies = ["com.fasterxml.jackson.core:jackson-databind"] +ecosystems = ["java"] + +[taxonomy] +role = ["library"] +function = ["serialization", "parsing"] +layer = ["backend"] + +[[security.sinks]] +symbol = "enableDefaultTyping" +threat = "deserialization" +cwe = "CWE-502" +note = "Polymorphic deserialization with gadget chains; dozens of CVEs" + +[[security.sinks]] +symbol = "@JsonTypeInfo" +threat = "deserialization" +cwe = "CWE-502" +note = "With use=Id.CLASS or Id.MINIMAL_CLASS" + +[[security.sinks]] +symbol = "readValue" +threat = "deserialization" +cwe = "CWE-502" +note = "When target type uses polymorphic typing" diff --git a/knowledge/java/okhttp.toml b/knowledge/java/okhttp.toml new file mode 100644 index 0000000..bffc846 --- /dev/null +++ b/knowledge/java/okhttp.toml @@ -0,0 +1,26 @@ +[tool] +name = "OkHttp" +category = "build" +homepage = "https://square.github.io/okhttp" +docs = "https://square.github.io/okhttp" +repo = "https://github.com/square/okhttp" +description = "HTTP client for JVM and Android" + +[detect] +dependencies = ["com.squareup.okhttp3:okhttp"] +ecosystems = ["java"] + +[taxonomy] +role = ["library"] +function = ["http-client"] +layer = ["backend"] + +[[security.sinks]] +symbol = "OkHttpClient.newCall" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "Request.Builder.url" +threat = "ssrf" +cwe = "CWE-918" diff --git a/knowledge/java/snakeyaml.toml b/knowledge/java/snakeyaml.toml new file mode 100644 index 0000000..437f615 --- /dev/null +++ b/knowledge/java/snakeyaml.toml @@ -0,0 +1,27 @@ +[tool] +name = "SnakeYAML" +category = "build" +homepage = "https://bitbucket.org/snakeyaml/snakeyaml" +docs = "https://bitbucket.org/snakeyaml/snakeyaml" +repo = "https://bitbucket.org/snakeyaml/snakeyaml" +description = "YAML parser for Java" + +[detect] +dependencies = ["org.yaml:snakeyaml"] +ecosystems = ["java"] + +[taxonomy] +role = ["library"] +function = ["serialization", "parsing"] +layer = ["backend"] + +[[security.sinks]] +symbol = "Yaml.load" +threat = "deserialization" +cwe = "CWE-502" +note = "Default Constructor allows arbitrary types; use SafeConstructor; CVE-2022-1471" + +[[security.sinks]] +symbol = "Yaml(new Constructor())" +threat = "deserialization" +cwe = "CWE-502" diff --git a/knowledge/java/thymeleaf.toml b/knowledge/java/thymeleaf.toml new file mode 100644 index 0000000..4bc42c1 --- /dev/null +++ b/knowledge/java/thymeleaf.toml @@ -0,0 +1,34 @@ +[tool] +name = "Thymeleaf" +category = "build" +homepage = "https://www.thymeleaf.org" +docs = "https://www.thymeleaf.org" +repo = "https://github.com/thymeleaf/thymeleaf" +description = "Server-side Java template engine" + +[detect] +dependencies = ["org.thymeleaf:thymeleaf", "org.springframework.boot:spring-boot-starter-thymeleaf"] +ecosystems = ["java"] + +[taxonomy] +role = ["library"] +function = ["templating"] +layer = ["backend"] + +[[security.sinks]] +symbol = "th:utext" +threat = "xss" +cwe = "CWE-79" +note = "Unescaped text; th:text is escaped" + +[[security.sinks]] +symbol = "[(" +threat = "xss" +cwe = "CWE-79" +note = "Inline unescaped expression" + +[[security.sinks]] +symbol = "SpringTemplateEngine.process" +threat = "ssti" +cwe = "CWE-1336" +note = "When template name is caller-controlled; SpEL evaluation" diff --git a/knowledge/java/xstream.toml b/knowledge/java/xstream.toml new file mode 100644 index 0000000..f124e72 --- /dev/null +++ b/knowledge/java/xstream.toml @@ -0,0 +1,22 @@ +[tool] +name = "XStream" +category = "build" +homepage = "https://x-stream.github.io" +docs = "https://x-stream.github.io" +repo = "https://github.com/x-stream/xstream" +description = "XML serialization for Java" + +[detect] +dependencies = ["com.thoughtworks.xstream:xstream"] +ecosystems = ["java"] + +[taxonomy] +role = ["library"] +function = ["serialization", "parsing"] +layer = ["backend"] + +[[security.sinks]] +symbol = "XStream.fromXML" +threat = "deserialization" +cwe = "CWE-502" +note = "Without security framework configured; many CVEs" diff --git a/knowledge/node/axios.toml b/knowledge/node/axios.toml new file mode 100644 index 0000000..07d74b0 --- /dev/null +++ b/knowledge/node/axios.toml @@ -0,0 +1,37 @@ +[tool] +name = "axios" +category = "build" +homepage = "https://axios-http.com" +docs = "https://axios-http.com" +repo = "https://github.com/axios/axios" +description = "Promise-based HTTP client" + +[detect] +dependencies = ["axios"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["http-client"] +layer = ["backend", "frontend"] + +[[security.sinks]] +symbol = "axios.get" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "axios.post" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "axios.request" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "axios.create" +threat = "ssrf" +cwe = "CWE-918" +note = "When baseURL is caller-controlled" diff --git a/knowledge/node/bcrypt-js.toml b/knowledge/node/bcrypt-js.toml new file mode 100644 index 0000000..39abc8f --- /dev/null +++ b/knowledge/node/bcrypt-js.toml @@ -0,0 +1,28 @@ +[tool] +name = "bcrypt" +category = "build" +homepage = "https://github.com/kelektiv/node.bcrypt.js" +docs = "https://github.com/kelektiv/node.bcrypt.js" +repo = "https://github.com/kelektiv/node.bcrypt.js" +description = "Password hashing" + +[detect] +dependencies = ["bcrypt", "bcryptjs"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["encryption", "authentication"] +layer = ["backend"] + +[[security.sinks]] +symbol = "bcrypt.hash" +threat = "weak_crypto" +cwe = "CWE-916" +note = "Truncates input at 72 bytes silently; cost factor too low" + +[[security.sinks]] +symbol = "bcrypt.compare" +threat = "auth_bypass" +cwe = "CWE-697" +note = "Returns false on error in some versions; check for null" diff --git a/knowledge/node/crypto-js.toml b/knowledge/node/crypto-js.toml new file mode 100644 index 0000000..f2bff75 --- /dev/null +++ b/knowledge/node/crypto-js.toml @@ -0,0 +1,42 @@ +[tool] +name = "crypto-js" +category = "build" +homepage = "https://github.com/brix/crypto-js" +docs = "https://github.com/brix/crypto-js" +repo = "https://github.com/brix/crypto-js" +description = "JavaScript crypto standards" + +[detect] +dependencies = ["crypto-js"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["encryption"] +layer = ["frontend", "backend"] + +[[security.sinks]] +symbol = "CryptoJS.MD5" +threat = "weak_crypto" +cwe = "CWE-327" + +[[security.sinks]] +symbol = "CryptoJS.SHA1" +threat = "weak_crypto" +cwe = "CWE-327" + +[[security.sinks]] +symbol = "CryptoJS.DES" +threat = "weak_crypto" +cwe = "CWE-327" + +[[security.sinks]] +symbol = "CryptoJS.RC4" +threat = "weak_crypto" +cwe = "CWE-327" + +[[security.sinks]] +symbol = "CryptoJS.AES.encrypt" +threat = "weak_crypto" +cwe = "CWE-327" +note = "Default mode/padding may not match expectations; CVE-2023-46233" diff --git a/knowledge/node/ejs.toml b/knowledge/node/ejs.toml new file mode 100644 index 0000000..a2274ab --- /dev/null +++ b/knowledge/node/ejs.toml @@ -0,0 +1,34 @@ +[tool] +name = "EJS" +category = "build" +homepage = "https://ejs.co" +docs = "https://ejs.co" +repo = "https://github.com/mde/ejs" +description = "Embedded JavaScript templates" + +[detect] +dependencies = ["ejs"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["templating"] +layer = ["backend"] + +[[security.sinks]] +symbol = "<%-" +threat = "xss" +cwe = "CWE-79" +note = "Unescaped output tag; <%= is escaped" + +[[security.sinks]] +symbol = "ejs.render" +threat = "ssti" +cwe = "CWE-1336" +note = "When template string is caller-controlled; CVE-2022-29078" + +[[security.sinks]] +symbol = "ejs.renderFile" +threat = "path_traversal" +cwe = "CWE-22" +note = "When filename is caller-controlled" diff --git a/knowledge/node/execa.toml b/knowledge/node/execa.toml new file mode 100644 index 0000000..4e008cf --- /dev/null +++ b/knowledge/node/execa.toml @@ -0,0 +1,34 @@ +[tool] +name = "execa" +category = "build" +homepage = "https://github.com/sindresorhus/execa" +docs = "https://github.com/sindresorhus/execa" +repo = "https://github.com/sindresorhus/execa" +description = "Process execution for Node.js" + +[detect] +dependencies = ["execa"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["process-execution"] +layer = ["backend"] + +[[security.sinks]] +symbol = "execa" +threat = "command_injection" +cwe = "CWE-78" +note = "Array form is safe; shell:true or execaCommand are not" + +[[security.sinks]] +symbol = "execaCommand" +threat = "command_injection" +cwe = "CWE-78" +note = "Parses string into shell command" + +[[security.sinks]] +symbol = "$" +threat = "command_injection" +cwe = "CWE-78" +note = "Template tag; interpolations are escaped but verify" diff --git a/knowledge/node/fast-xml-parser.toml b/knowledge/node/fast-xml-parser.toml new file mode 100644 index 0000000..7431aa4 --- /dev/null +++ b/knowledge/node/fast-xml-parser.toml @@ -0,0 +1,22 @@ +[tool] +name = "fast-xml-parser" +category = "build" +homepage = "https://github.com/NaturalIntelligence/fast-xml-parser" +docs = "https://github.com/NaturalIntelligence/fast-xml-parser" +repo = "https://github.com/NaturalIntelligence/fast-xml-parser" +description = "Fast XML parser without C/C++ deps" + +[detect] +dependencies = ["fast-xml-parser"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["parsing"] +layer = ["backend"] + +[[security.sinks]] +symbol = "XMLParser" +threat = "dos" +cwe = "CWE-400" +note = "No XXE since no DTD support; entity expansion DoS possible" diff --git a/knowledge/node/formidable.toml b/knowledge/node/formidable.toml new file mode 100644 index 0000000..0624a42 --- /dev/null +++ b/knowledge/node/formidable.toml @@ -0,0 +1,28 @@ +[tool] +name = "Formidable" +category = "build" +homepage = "https://github.com/node-formidable/formidable" +docs = "https://github.com/node-formidable/formidable" +repo = "https://github.com/node-formidable/formidable" +description = "Form data parser" + +[detect] +dependencies = ["formidable"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["file-management", "parsing"] +layer = ["backend"] + +[[security.sinks]] +symbol = "uploadDir" +threat = "path_traversal" +cwe = "CWE-22" +note = "When derived from request data" + +[[security.sinks]] +symbol = "originalFilename" +threat = "path_traversal" +cwe = "CWE-22" +note = "Client-controlled" diff --git a/knowledge/node/got.toml b/knowledge/node/got.toml new file mode 100644 index 0000000..ed001fc --- /dev/null +++ b/knowledge/node/got.toml @@ -0,0 +1,31 @@ +[tool] +name = "got" +category = "build" +homepage = "https://github.com/sindresorhus/got" +docs = "https://github.com/sindresorhus/got" +repo = "https://github.com/sindresorhus/got" +description = "HTTP request library for Node.js" + +[detect] +dependencies = ["got"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["http-client"] +layer = ["backend"] + +[[security.sinks]] +symbol = "got" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "got.get" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "got.post" +threat = "ssrf" +cwe = "CWE-918" diff --git a/knowledge/node/handlebars.toml b/knowledge/node/handlebars.toml new file mode 100644 index 0000000..29475b8 --- /dev/null +++ b/knowledge/node/handlebars.toml @@ -0,0 +1,34 @@ +[tool] +name = "Handlebars" +category = "build" +homepage = "https://handlebarsjs.com" +docs = "https://handlebarsjs.com" +repo = "https://github.com/handlebars-lang/handlebars.js" +description = "Logic-less templates" + +[detect] +dependencies = ["handlebars"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["templating"] +layer = ["backend", "frontend"] + +[[security.sinks]] +symbol = "{{{" +threat = "xss" +cwe = "CWE-79" +note = "Triple-stash unescaped; {{ }} is escaped" + +[[security.sinks]] +symbol = "SafeString" +threat = "xss" +cwe = "CWE-79" +note = "Marks string as pre-escaped" + +[[security.sinks]] +symbol = "compile" +threat = "ssti" +cwe = "CWE-1336" +note = "When template string is caller-controlled; prototype pollution gadgets" diff --git a/knowledge/node/js-yaml.toml b/knowledge/node/js-yaml.toml new file mode 100644 index 0000000..cb04fa4 --- /dev/null +++ b/knowledge/node/js-yaml.toml @@ -0,0 +1,28 @@ +[tool] +name = "js-yaml" +category = "build" +homepage = "https://github.com/nodeca/js-yaml" +docs = "https://github.com/nodeca/js-yaml" +repo = "https://github.com/nodeca/js-yaml" +description = "YAML parser for JavaScript" + +[detect] +dependencies = ["js-yaml"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["serialization", "parsing"] +layer = ["backend"] + +[[security.sinks]] +symbol = "yaml.load" +threat = "deserialization" +cwe = "CWE-502" +note = "Pre-4.0 default schema allowed !!js/function; safe in 4.x" + +[[security.sinks]] +symbol = "DEFAULT_FULL_SCHEMA" +threat = "deserialization" +cwe = "CWE-502" +note = "Pre-4.0 schema with !!js/* tags" diff --git a/knowledge/node/jsonwebtoken.toml b/knowledge/node/jsonwebtoken.toml new file mode 100644 index 0000000..4910d60 --- /dev/null +++ b/knowledge/node/jsonwebtoken.toml @@ -0,0 +1,28 @@ +[tool] +name = "jsonwebtoken" +category = "build" +homepage = "https://github.com/auth0/node-jsonwebtoken" +docs = "https://github.com/auth0/node-jsonwebtoken" +repo = "https://github.com/auth0/node-jsonwebtoken" +description = "JWT implementation for Node.js" + +[detect] +dependencies = ["jsonwebtoken"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["authentication"] +layer = ["backend"] + +[[security.sinks]] +symbol = "jwt.verify" +threat = "auth_bypass" +cwe = "CWE-347" +note = "Without algorithms option; CVE-2022-23529 class" + +[[security.sinks]] +symbol = "jwt.decode" +threat = "auth_bypass" +cwe = "CWE-347" +note = "Does not verify signature, only decodes" diff --git a/knowledge/node/multer.toml b/knowledge/node/multer.toml new file mode 100644 index 0000000..5ec707d --- /dev/null +++ b/knowledge/node/multer.toml @@ -0,0 +1,28 @@ +[tool] +name = "Multer" +category = "build" +homepage = "https://github.com/expressjs/multer" +docs = "https://github.com/expressjs/multer" +repo = "https://github.com/expressjs/multer" +description = "Multipart form data middleware" + +[detect] +dependencies = ["multer"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["file-management"] +layer = ["backend"] + +[[security.sinks]] +symbol = "diskStorage" +threat = "path_traversal" +cwe = "CWE-22" +note = "When destination/filename use req fields without sanitization" + +[[security.sinks]] +symbol = "originalname" +threat = "path_traversal" +cwe = "CWE-22" +note = "Client-controlled, may contain ../" diff --git a/knowledge/node/mustache-js.toml b/knowledge/node/mustache-js.toml new file mode 100644 index 0000000..027450a --- /dev/null +++ b/knowledge/node/mustache-js.toml @@ -0,0 +1,28 @@ +[tool] +name = "Mustache" +category = "build" +homepage = "https://github.com/janl/mustache.js" +docs = "https://github.com/janl/mustache.js" +repo = "https://github.com/janl/mustache.js" +description = "Logic-less templates" + +[detect] +dependencies = ["mustache"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["templating"] +layer = ["backend", "frontend"] + +[[security.sinks]] +symbol = "{{{" +threat = "xss" +cwe = "CWE-79" +note = "Triple mustache unescaped" + +[[security.sinks]] +symbol = "{{&" +threat = "xss" +cwe = "CWE-79" +note = "Ampersand unescaped" diff --git a/knowledge/node/next-auth.toml b/knowledge/node/next-auth.toml new file mode 100644 index 0000000..c0f1f07 --- /dev/null +++ b/knowledge/node/next-auth.toml @@ -0,0 +1,28 @@ +[tool] +name = "NextAuth.js" +category = "build" +homepage = "https://next-auth.js.org" +docs = "https://next-auth.js.org" +repo = "https://github.com/nextauthjs/next-auth" +description = "Authentication for Next.js" + +[detect] +dependencies = ["next-auth"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["authentication"] +layer = ["backend", "full-stack"] + +[[security.sinks]] +symbol = "callbacks.signIn" +threat = "auth_bypass" +cwe = "CWE-287" +note = "Returning true unconditionally" + +[[security.sinks]] +symbol = "NEXTAUTH_SECRET" +threat = "auth_bypass" +cwe = "CWE-321" +note = "Missing or weak secret in production" diff --git a/knowledge/node/node-fetch.toml b/knowledge/node/node-fetch.toml new file mode 100644 index 0000000..6069539 --- /dev/null +++ b/knowledge/node/node-fetch.toml @@ -0,0 +1,21 @@ +[tool] +name = "node-fetch" +category = "build" +homepage = "https://github.com/node-fetch/node-fetch" +docs = "https://github.com/node-fetch/node-fetch" +repo = "https://github.com/node-fetch/node-fetch" +description = "Fetch API for Node.js" + +[detect] +dependencies = ["node-fetch"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["http-client"] +layer = ["backend"] + +[[security.sinks]] +symbol = "fetch" +threat = "ssrf" +cwe = "CWE-918" diff --git a/knowledge/node/nunjucks.toml b/knowledge/node/nunjucks.toml new file mode 100644 index 0000000..16ccc95 --- /dev/null +++ b/knowledge/node/nunjucks.toml @@ -0,0 +1,33 @@ +[tool] +name = "Nunjucks" +category = "build" +homepage = "https://mozilla.github.io/nunjucks" +docs = "https://mozilla.github.io/nunjucks" +repo = "https://github.com/mozilla/nunjucks" +description = "Jinja2-inspired templating for JavaScript" + +[detect] +dependencies = ["nunjucks"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["templating"] +layer = ["backend"] + +[[security.sinks]] +symbol = "|safe" +threat = "xss" +cwe = "CWE-79" + +[[security.sinks]] +symbol = "renderString" +threat = "ssti" +cwe = "CWE-1336" +note = "When template is caller-controlled" + +[[security.sinks]] +symbol = "configure" +threat = "ssti" +cwe = "CWE-1336" +note = "autoescape: false" diff --git a/knowledge/node/passport.toml b/knowledge/node/passport.toml new file mode 100644 index 0000000..21f8cd2 --- /dev/null +++ b/knowledge/node/passport.toml @@ -0,0 +1,28 @@ +[tool] +name = "Passport" +category = "build" +homepage = "https://www.passportjs.org" +docs = "https://www.passportjs.org" +repo = "https://github.com/jaredhanson/passport" +description = "Authentication middleware for Node.js" + +[detect] +dependencies = ["passport"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["authentication"] +layer = ["backend"] + +[[security.sinks]] +symbol = "passport.authenticate" +threat = "auth_bypass" +cwe = "CWE-287" +note = "Strategy misconfiguration; check failureRedirect" + +[[security.sinks]] +symbol = "req.login" +threat = "session_fixation" +cwe = "CWE-384" +note = "Without session regeneration" diff --git a/knowledge/node/pug.toml b/knowledge/node/pug.toml new file mode 100644 index 0000000..ea520da --- /dev/null +++ b/knowledge/node/pug.toml @@ -0,0 +1,39 @@ +[tool] +name = "Pug" +category = "build" +homepage = "https://pugjs.org" +docs = "https://pugjs.org" +repo = "https://github.com/pugjs/pug" +description = "Template engine for Node.js" + +[detect] +dependencies = ["pug"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["templating"] +layer = ["backend"] + +[[security.sinks]] +symbol = "!{" +threat = "xss" +cwe = "CWE-79" +note = "Unescaped interpolation; #{} is escaped" + +[[security.sinks]] +symbol = "!=" +threat = "xss" +cwe = "CWE-79" +note = "Unescaped buffered code" + +[[security.sinks]] +symbol = "pug.compile" +threat = "ssti" +cwe = "CWE-1336" +note = "When template string is caller-controlled" + +[[security.sinks]] +symbol = "pug.render" +threat = "ssti" +cwe = "CWE-1336" diff --git a/knowledge/node/shelljs.toml b/knowledge/node/shelljs.toml new file mode 100644 index 0000000..287c7b6 --- /dev/null +++ b/knowledge/node/shelljs.toml @@ -0,0 +1,21 @@ +[tool] +name = "ShellJS" +category = "build" +homepage = "https://github.com/shelljs/shelljs" +docs = "https://github.com/shelljs/shelljs" +repo = "https://github.com/shelljs/shelljs" +description = "Unix shell commands for Node.js" + +[detect] +dependencies = ["shelljs"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["process-execution"] +layer = ["backend"] + +[[security.sinks]] +symbol = "shell.exec" +threat = "command_injection" +cwe = "CWE-78" diff --git a/knowledge/node/undici.toml b/knowledge/node/undici.toml new file mode 100644 index 0000000..4327d38 --- /dev/null +++ b/knowledge/node/undici.toml @@ -0,0 +1,26 @@ +[tool] +name = "undici" +category = "build" +homepage = "https://undici.nodejs.org" +docs = "https://undici.nodejs.org" +repo = "https://github.com/nodejs/undici" +description = "HTTP client written from scratch for Node.js" + +[detect] +dependencies = ["undici"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["http-client"] +layer = ["backend"] + +[[security.sinks]] +symbol = "fetch" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "request" +threat = "ssrf" +cwe = "CWE-918" diff --git a/knowledge/node/xml2js.toml b/knowledge/node/xml2js.toml new file mode 100644 index 0000000..7928441 --- /dev/null +++ b/knowledge/node/xml2js.toml @@ -0,0 +1,28 @@ +[tool] +name = "xml2js" +category = "build" +homepage = "https://github.com/Leonidas-from-XIV/node-xml2js" +docs = "https://github.com/Leonidas-from-XIV/node-xml2js" +repo = "https://github.com/Leonidas-from-XIV/node-xml2js" +description = "XML to JavaScript object converter" + +[detect] +dependencies = ["xml2js"] +ecosystems = ["node"] + +[taxonomy] +role = ["library"] +function = ["parsing"] +layer = ["backend"] + +[[security.sinks]] +symbol = "parseString" +threat = "xxe" +cwe = "CWE-611" +note = "Underlying sax parser; entity expansion DoS more likely than XXE" + +[[security.sinks]] +symbol = "Parser" +threat = "dos" +cwe = "CWE-400" +note = "Billion-laughs without explicitChildren limits" diff --git a/knowledge/php/guzzle.toml b/knowledge/php/guzzle.toml new file mode 100644 index 0000000..89d7d0c --- /dev/null +++ b/knowledge/php/guzzle.toml @@ -0,0 +1,31 @@ +[tool] +name = "Guzzle" +category = "build" +homepage = "https://docs.guzzlephp.org" +docs = "https://docs.guzzlephp.org" +repo = "https://github.com/guzzle/guzzle" +description = "HTTP client for PHP" + +[detect] +dependencies = ["guzzlehttp/guzzle"] +ecosystems = ["php"] + +[taxonomy] +role = ["library"] +function = ["http-client"] +layer = ["backend"] + +[[security.sinks]] +symbol = "Client::get" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "Client::post" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "Client::request" +threat = "ssrf" +cwe = "CWE-918" diff --git a/knowledge/php/twig.toml b/knowledge/php/twig.toml new file mode 100644 index 0000000..19c0f20 --- /dev/null +++ b/knowledge/php/twig.toml @@ -0,0 +1,34 @@ +[tool] +name = "Twig" +category = "build" +homepage = "https://twig.symfony.com" +docs = "https://twig.symfony.com" +repo = "https://github.com/twigphp/Twig" +description = "Template engine for PHP" + +[detect] +dependencies = ["twig/twig"] +ecosystems = ["php"] + +[taxonomy] +role = ["library"] +function = ["templating"] +layer = ["backend"] + +[[security.sinks]] +symbol = "|raw" +threat = "xss" +cwe = "CWE-79" +note = "Filter that bypasses autoescaping" + +[[security.sinks]] +symbol = "autoescape false" +threat = "xss" +cwe = "CWE-79" +note = "Block tag" + +[[security.sinks]] +symbol = "createTemplate" +threat = "ssti" +cwe = "CWE-1336" +note = "When template string is caller-controlled" diff --git a/knowledge/python/aiohttp.toml b/knowledge/python/aiohttp.toml new file mode 100644 index 0000000..b88aba6 --- /dev/null +++ b/knowledge/python/aiohttp.toml @@ -0,0 +1,26 @@ +[tool] +name = "aiohttp" +category = "build" +homepage = "https://docs.aiohttp.org" +docs = "https://docs.aiohttp.org" +repo = "https://github.com/aio-libs/aiohttp" +description = "Async HTTP client/server for Python" + +[detect] +dependencies = ["aiohttp"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["http-client", "api-development"] +layer = ["backend"] + +[[security.sinks]] +symbol = "ClientSession.get" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "ClientSession.request" +threat = "ssrf" +cwe = "CWE-918" diff --git a/knowledge/python/authlib.toml b/knowledge/python/authlib.toml new file mode 100644 index 0000000..0c86f53 --- /dev/null +++ b/knowledge/python/authlib.toml @@ -0,0 +1,22 @@ +[tool] +name = "Authlib" +category = "build" +homepage = "https://authlib.org" +docs = "https://authlib.org" +repo = "https://github.com/lepture/authlib" +description = "OAuth and OpenID Connect library" + +[detect] +dependencies = ["authlib", "Authlib"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["authentication"] +layer = ["backend"] + +[[security.sinks]] +symbol = "jwt.decode" +threat = "auth_bypass" +cwe = "CWE-347" +note = "Verify alg claim against expected" diff --git a/knowledge/python/cryptography.toml b/knowledge/python/cryptography.toml new file mode 100644 index 0000000..031bcbe --- /dev/null +++ b/knowledge/python/cryptography.toml @@ -0,0 +1,28 @@ +[tool] +name = "cryptography" +category = "build" +homepage = "https://cryptography.io" +docs = "https://cryptography.io" +repo = "https://github.com/pyca/cryptography" +description = "Cryptographic recipes and primitives" + +[detect] +dependencies = ["cryptography"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["encryption"] +layer = ["backend"] + +[[security.sinks]] +symbol = "hazmat" +threat = "weak_crypto" +cwe = "CWE-327" +note = "hazmat layer is intentionally low-level; misuse is easy" + +[[security.sinks]] +symbol = "ECB" +threat = "weak_crypto" +cwe = "CWE-327" +note = "modes.ECB() leaks plaintext patterns" diff --git a/knowledge/python/defusedxml.toml b/knowledge/python/defusedxml.toml new file mode 100644 index 0000000..d598e3d --- /dev/null +++ b/knowledge/python/defusedxml.toml @@ -0,0 +1,16 @@ +[tool] +name = "defusedxml" +category = "build" +homepage = "https://github.com/tiran/defusedxml" +docs = "https://github.com/tiran/defusedxml" +repo = "https://github.com/tiran/defusedxml" +description = "XML parser wrappers that block XXE and billion-laughs" + +[detect] +dependencies = ["defusedxml"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["parsing"] +layer = ["backend"] diff --git a/knowledge/python/httpx.toml b/knowledge/python/httpx.toml new file mode 100644 index 0000000..27d3a0f --- /dev/null +++ b/knowledge/python/httpx.toml @@ -0,0 +1,31 @@ +[tool] +name = "httpx" +category = "build" +homepage = "https://www.python-httpx.org" +docs = "https://www.python-httpx.org" +repo = "https://github.com/encode/httpx" +description = "Async HTTP client for Python" + +[detect] +dependencies = ["httpx"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["http-client"] +layer = ["backend"] + +[[security.sinks]] +symbol = "httpx.get" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "httpx.post" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "AsyncClient.get" +threat = "ssrf" +cwe = "CWE-918" diff --git a/knowledge/python/invoke.toml b/knowledge/python/invoke.toml new file mode 100644 index 0000000..cf3043c --- /dev/null +++ b/knowledge/python/invoke.toml @@ -0,0 +1,27 @@ +[tool] +name = "Invoke" +category = "build" +homepage = "https://www.pyinvoke.org" +docs = "https://www.pyinvoke.org" +repo = "https://github.com/pyinvoke/invoke" +description = "Task execution and command running" + +[detect] +dependencies = ["invoke"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["process-execution", "automation"] +layer = ["backend"] + +[[security.sinks]] +symbol = "Context.run" +threat = "command_injection" +cwe = "CWE-78" +note = "Runs through shell by default" + +[[security.sinks]] +symbol = "c.run" +threat = "command_injection" +cwe = "CWE-78" diff --git a/knowledge/python/jinja2.toml b/knowledge/python/jinja2.toml new file mode 100644 index 0000000..0050384 --- /dev/null +++ b/knowledge/python/jinja2.toml @@ -0,0 +1,45 @@ +[tool] +name = "Jinja2" +category = "build" +homepage = "https://jinja.palletsprojects.com" +docs = "https://jinja.palletsprojects.com" +repo = "https://github.com/pallets/jinja" +description = "Template engine for Python" + +[detect] +dependencies = ["jinja2", "Jinja2"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["templating"] +layer = ["backend"] + +[[security.sinks]] +symbol = "Markup" +threat = "xss" +cwe = "CWE-79" +note = "Bypasses autoescaping" + +[[security.sinks]] +symbol = "|safe" +threat = "xss" +cwe = "CWE-79" +note = "Filter that bypasses escaping" + +[[security.sinks]] +symbol = "Environment" +threat = "ssti" +cwe = "CWE-1336" +note = "When autoescape=False or template source is caller-controlled" + +[[security.sinks]] +symbol = "Template" +threat = "ssti" +cwe = "CWE-1336" +note = "When template source string is caller-controlled" + +[[security.sinks]] +symbol = "from_string" +threat = "ssti" +cwe = "CWE-1336" diff --git a/knowledge/python/lxml.toml b/knowledge/python/lxml.toml new file mode 100644 index 0000000..fa13442 --- /dev/null +++ b/knowledge/python/lxml.toml @@ -0,0 +1,38 @@ +[tool] +name = "lxml" +category = "build" +homepage = "https://lxml.de" +docs = "https://lxml.de" +repo = "https://github.com/lxml/lxml" +description = "XML and HTML processing library" + +[detect] +dependencies = ["lxml"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["parsing"] +layer = ["backend"] + +[[security.sinks]] +symbol = "etree.parse" +threat = "xxe" +cwe = "CWE-611" +note = "Without resolve_entities=False on the parser" + +[[security.sinks]] +symbol = "etree.fromstring" +threat = "xxe" +cwe = "CWE-611" + +[[security.sinks]] +symbol = "etree.XMLParser" +threat = "xxe" +cwe = "CWE-611" +note = "Default resolve_entities=True" + +[[security.sinks]] +symbol = "objectify.parse" +threat = "xxe" +cwe = "CWE-611" diff --git a/knowledge/python/mako.toml b/knowledge/python/mako.toml new file mode 100644 index 0000000..41011a2 --- /dev/null +++ b/knowledge/python/mako.toml @@ -0,0 +1,28 @@ +[tool] +name = "Mako" +category = "build" +homepage = "https://www.makotemplates.org" +docs = "https://www.makotemplates.org" +repo = "https://github.com/sqlalchemy/mako" +description = "Template library for Python" + +[detect] +dependencies = ["mako", "Mako"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["templating"] +layer = ["backend"] + +[[security.sinks]] +symbol = "Template" +threat = "ssti" +cwe = "CWE-1336" +note = "No autoescaping by default; template source is Python" + +[[security.sinks]] +symbol = "|n" +threat = "xss" +cwe = "CWE-79" +note = "Disables filtering" diff --git a/knowledge/python/pycryptodome.toml b/knowledge/python/pycryptodome.toml new file mode 100644 index 0000000..c77c584 --- /dev/null +++ b/knowledge/python/pycryptodome.toml @@ -0,0 +1,31 @@ +[tool] +name = "PyCryptodome" +category = "build" +homepage = "https://www.pycryptodome.org" +docs = "https://www.pycryptodome.org" +repo = "https://github.com/Legrandin/pycryptodome" +description = "Cryptographic library for Python" + +[detect] +dependencies = ["pycryptodome", "pycryptodomex"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["encryption"] +layer = ["backend"] + +[[security.sinks]] +symbol = "DES.new" +threat = "weak_crypto" +cwe = "CWE-327" + +[[security.sinks]] +symbol = "ARC4.new" +threat = "weak_crypto" +cwe = "CWE-327" + +[[security.sinks]] +symbol = "MODE_ECB" +threat = "weak_crypto" +cwe = "CWE-327" diff --git a/knowledge/python/pyjwt.toml b/knowledge/python/pyjwt.toml new file mode 100644 index 0000000..9399bb5 --- /dev/null +++ b/knowledge/python/pyjwt.toml @@ -0,0 +1,28 @@ +[tool] +name = "PyJWT" +category = "build" +homepage = "https://pyjwt.readthedocs.io" +docs = "https://pyjwt.readthedocs.io" +repo = "https://github.com/jpadilla/pyjwt" +description = "JSON Web Token implementation" + +[detect] +dependencies = ["pyjwt", "PyJWT"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["authentication"] +layer = ["backend"] + +[[security.sinks]] +symbol = "jwt.decode" +threat = "auth_bypass" +cwe = "CWE-347" +note = "Without algorithms= explicitly set; alg=none CVE-2015-9235 class" + +[[security.sinks]] +symbol = "verify=False" +threat = "auth_bypass" +cwe = "CWE-347" +note = "Disables signature verification" diff --git a/knowledge/python/python-jose.toml b/knowledge/python/python-jose.toml new file mode 100644 index 0000000..04cb801 --- /dev/null +++ b/knowledge/python/python-jose.toml @@ -0,0 +1,22 @@ +[tool] +name = "python-jose" +category = "build" +homepage = "https://github.com/mpdavis/python-jose" +docs = "https://github.com/mpdavis/python-jose" +repo = "https://github.com/mpdavis/python-jose" +description = "JOSE implementation for Python" + +[detect] +dependencies = ["python-jose"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["authentication", "encryption"] +layer = ["backend"] + +[[security.sinks]] +symbol = "jwt.decode" +threat = "auth_bypass" +cwe = "CWE-347" +note = "Algorithm confusion; CVE-2024-33663" diff --git a/knowledge/python/python-multipart.toml b/knowledge/python/python-multipart.toml new file mode 100644 index 0000000..4aff84b --- /dev/null +++ b/knowledge/python/python-multipart.toml @@ -0,0 +1,22 @@ +[tool] +name = "python-multipart" +category = "build" +homepage = "https://github.com/Kludex/python-multipart" +docs = "https://github.com/Kludex/python-multipart" +repo = "https://github.com/Kludex/python-multipart" +description = "Streaming multipart parser" + +[detect] +dependencies = ["python-multipart"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["file-management", "parsing"] +layer = ["backend"] + +[[security.sinks]] +symbol = "filename" +threat = "path_traversal" +cwe = "CWE-22" +note = "From Content-Disposition header, client-controlled" diff --git a/knowledge/python/pyyaml.toml b/knowledge/python/pyyaml.toml new file mode 100644 index 0000000..5c68fb9 --- /dev/null +++ b/knowledge/python/pyyaml.toml @@ -0,0 +1,33 @@ +[tool] +name = "PyYAML" +category = "build" +homepage = "https://pyyaml.org" +docs = "https://pyyaml.org" +repo = "https://github.com/yaml/pyyaml" +description = "YAML parser and emitter for Python" + +[detect] +dependencies = ["pyyaml", "PyYAML"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["serialization", "parsing"] +layer = ["backend"] + +[[security.sinks]] +symbol = "yaml.load" +threat = "deserialization" +cwe = "CWE-502" +note = "Without Loader=SafeLoader; constructs arbitrary Python objects" + +[[security.sinks]] +symbol = "yaml.unsafe_load" +threat = "deserialization" +cwe = "CWE-502" + +[[security.sinks]] +symbol = "yaml.full_load" +threat = "deserialization" +cwe = "CWE-502" +note = "Less dangerous than load but still allows some object construction" diff --git a/knowledge/python/requests.toml b/knowledge/python/requests.toml new file mode 100644 index 0000000..232b9f2 --- /dev/null +++ b/knowledge/python/requests.toml @@ -0,0 +1,37 @@ +[tool] +name = "requests" +category = "build" +homepage = "https://requests.readthedocs.io" +docs = "https://requests.readthedocs.io" +repo = "https://github.com/psf/requests" +description = "HTTP library for Python" + +[detect] +dependencies = ["requests"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["http-client"] +layer = ["backend"] + +[[security.sinks]] +symbol = "requests.get" +threat = "ssrf" +cwe = "CWE-918" +note = "When URL is caller-controlled" + +[[security.sinks]] +symbol = "requests.post" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "requests.request" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "Session.get" +threat = "ssrf" +cwe = "CWE-918" diff --git a/knowledge/python/ruamel-yaml.toml b/knowledge/python/ruamel-yaml.toml new file mode 100644 index 0000000..45a70b6 --- /dev/null +++ b/knowledge/python/ruamel-yaml.toml @@ -0,0 +1,27 @@ +[tool] +name = "ruamel.yaml" +category = "build" +homepage = "https://yaml.readthedocs.io" +docs = "https://yaml.readthedocs.io" +repo = "https://sourceforge.net/projects/ruamel-yaml" +description = "YAML parser with round-trip preservation" + +[detect] +dependencies = ["ruamel.yaml", "ruamel-yaml"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["serialization", "parsing"] +layer = ["backend"] + +[[security.sinks]] +symbol = "YAML(typ=\"unsafe\")" +threat = "deserialization" +cwe = "CWE-502" + +[[security.sinks]] +symbol = "YAML().load" +threat = "deserialization" +cwe = "CWE-502" +note = "Default typ is rt which is safe; unsafe/full are not" diff --git a/knowledge/python/sh-py.toml b/knowledge/python/sh-py.toml new file mode 100644 index 0000000..5750d50 --- /dev/null +++ b/knowledge/python/sh-py.toml @@ -0,0 +1,22 @@ +[tool] +name = "sh" +category = "build" +homepage = "https://sh.readthedocs.io" +docs = "https://sh.readthedocs.io" +repo = "https://github.com/amoffat/sh" +description = "Subprocess interface for Python" + +[detect] +dependencies = ["sh"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["process-execution"] +layer = ["backend"] + +[[security.sinks]] +symbol = "sh.Command" +threat = "command_injection" +cwe = "CWE-78" +note = "When command name is caller-controlled" diff --git a/knowledge/python/urllib3.toml b/knowledge/python/urllib3.toml new file mode 100644 index 0000000..8c5fe8b --- /dev/null +++ b/knowledge/python/urllib3.toml @@ -0,0 +1,26 @@ +[tool] +name = "urllib3" +category = "build" +homepage = "https://urllib3.readthedocs.io" +docs = "https://urllib3.readthedocs.io" +repo = "https://github.com/urllib3/urllib3" +description = "HTTP client with connection pooling" + +[detect] +dependencies = ["urllib3"] +ecosystems = ["python"] + +[taxonomy] +role = ["library"] +function = ["http-client"] +layer = ["backend"] + +[[security.sinks]] +symbol = "PoolManager.request" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "urlopen" +threat = "ssrf" +cwe = "CWE-918" diff --git a/knowledge/ruby/bcrypt-rb.toml b/knowledge/ruby/bcrypt-rb.toml new file mode 100644 index 0000000..12a7fc5 --- /dev/null +++ b/knowledge/ruby/bcrypt-rb.toml @@ -0,0 +1,22 @@ +[tool] +name = "bcrypt-ruby" +category = "build" +homepage = "https://github.com/bcrypt-ruby/bcrypt-ruby" +docs = "https://github.com/bcrypt-ruby/bcrypt-ruby" +repo = "https://github.com/bcrypt-ruby/bcrypt-ruby" +description = "Password hashing" + +[detect] +dependencies = ["bcrypt"] +ecosystems = ["ruby"] + +[taxonomy] +role = ["library"] +function = ["encryption", "authentication"] +layer = ["backend"] + +[[security.sinks]] +symbol = "BCrypt::Password.create" +threat = "weak_crypto" +cwe = "CWE-916" +note = "Truncates at 72 bytes; cost too low" diff --git a/knowledge/ruby/carrierwave.toml b/knowledge/ruby/carrierwave.toml new file mode 100644 index 0000000..b84b1a8 --- /dev/null +++ b/knowledge/ruby/carrierwave.toml @@ -0,0 +1,28 @@ +[tool] +name = "CarrierWave" +category = "build" +homepage = "https://github.com/carrierwaveuploader/carrierwave" +docs = "https://github.com/carrierwaveuploader/carrierwave" +repo = "https://github.com/carrierwaveuploader/carrierwave" +description = "File upload solution for Rails" + +[detect] +dependencies = ["carrierwave"] +ecosystems = ["ruby"] + +[taxonomy] +role = ["library"] +function = ["file-management"] +layer = ["backend"] + +[[security.sinks]] +symbol = "original_filename" +threat = "path_traversal" +cwe = "CWE-22" +note = "Client-controlled; sanitize before use" + +[[security.sinks]] +symbol = "extension_allowlist" +threat = "auth_bypass" +cwe = "CWE-434" +note = "Missing allowlist permits arbitrary file types" diff --git a/knowledge/ruby/devise.toml b/knowledge/ruby/devise.toml new file mode 100644 index 0000000..44a894a --- /dev/null +++ b/knowledge/ruby/devise.toml @@ -0,0 +1,28 @@ +[tool] +name = "Devise" +category = "build" +homepage = "https://github.com/heartcombo/devise" +docs = "https://github.com/heartcombo/devise" +repo = "https://github.com/heartcombo/devise" +description = "Authentication solution for Rails" + +[detect] +dependencies = ["devise"] +ecosystems = ["ruby"] + +[taxonomy] +role = ["library"] +function = ["authentication"] +layer = ["backend"] + +[[security.sinks]] +symbol = "sign_in" +threat = "session_fixation" +cwe = "CWE-384" +note = "Without session reset; Devise handles by default but custom flows may not" + +[[security.sinks]] +symbol = "skip_before_action :authenticate_user!" +threat = "auth_bypass" +cwe = "CWE-287" +note = "Selective skips can leak" diff --git a/knowledge/ruby/faraday.toml b/knowledge/ruby/faraday.toml new file mode 100644 index 0000000..ce20dcd --- /dev/null +++ b/knowledge/ruby/faraday.toml @@ -0,0 +1,32 @@ +[tool] +name = "Faraday" +category = "build" +homepage = "https://lostisland.github.io/faraday" +docs = "https://lostisland.github.io/faraday" +repo = "https://github.com/lostisland/faraday" +description = "HTTP client library with middleware" + +[detect] +dependencies = ["faraday"] +ecosystems = ["ruby"] + +[taxonomy] +role = ["library"] +function = ["http-client"] +layer = ["backend"] + +[[security.sinks]] +symbol = "Faraday.get" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "Faraday.post" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "Faraday.new" +threat = "ssrf" +cwe = "CWE-918" +note = "When url is caller-controlled" diff --git a/knowledge/ruby/haml.toml b/knowledge/ruby/haml.toml new file mode 100644 index 0000000..da8078f --- /dev/null +++ b/knowledge/ruby/haml.toml @@ -0,0 +1,34 @@ +[tool] +name = "Haml" +category = "build" +homepage = "https://haml.info" +docs = "https://haml.info" +repo = "https://github.com/haml/haml" +description = "HTML abstraction markup language" + +[detect] +dependencies = ["haml"] +ecosystems = ["ruby"] + +[taxonomy] +role = ["library"] +function = ["templating"] +layer = ["backend"] + +[[security.sinks]] +symbol = "!=" +threat = "xss" +cwe = "CWE-79" +note = "Unescaped output; = is escaped" + +[[security.sinks]] +symbol = "!" +threat = "xss" +cwe = "CWE-79" +note = "Unescaped interpolation prefix" + +[[security.sinks]] +symbol = "Haml::Engine.new" +threat = "ssti" +cwe = "CWE-1336" +note = "When template string is caller-controlled" diff --git a/knowledge/ruby/httparty.toml b/knowledge/ruby/httparty.toml new file mode 100644 index 0000000..82f5674 --- /dev/null +++ b/knowledge/ruby/httparty.toml @@ -0,0 +1,26 @@ +[tool] +name = "HTTParty" +category = "build" +homepage = "https://github.com/jnunemaker/httparty" +docs = "https://github.com/jnunemaker/httparty" +repo = "https://github.com/jnunemaker/httparty" +description = "HTTP client with class-based API" + +[detect] +dependencies = ["httparty"] +ecosystems = ["ruby"] + +[taxonomy] +role = ["library"] +function = ["http-client"] +layer = ["backend"] + +[[security.sinks]] +symbol = "HTTParty.get" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "HTTParty.post" +threat = "ssrf" +cwe = "CWE-918" diff --git a/knowledge/ruby/jwt-rb.toml b/knowledge/ruby/jwt-rb.toml new file mode 100644 index 0000000..85bea06 --- /dev/null +++ b/knowledge/ruby/jwt-rb.toml @@ -0,0 +1,22 @@ +[tool] +name = "ruby-jwt" +category = "build" +homepage = "https://github.com/jwt/ruby-jwt" +docs = "https://github.com/jwt/ruby-jwt" +repo = "https://github.com/jwt/ruby-jwt" +description = "JWT implementation for Ruby" + +[detect] +dependencies = ["jwt"] +ecosystems = ["ruby"] + +[taxonomy] +role = ["library"] +function = ["authentication"] +layer = ["backend"] + +[[security.sinks]] +symbol = "JWT.decode" +threat = "auth_bypass" +cwe = "CWE-347" +note = "With verify=false or without algorithm restriction" diff --git a/knowledge/ruby/liquid.toml b/knowledge/ruby/liquid.toml new file mode 100644 index 0000000..a1fb128 --- /dev/null +++ b/knowledge/ruby/liquid.toml @@ -0,0 +1,22 @@ +[tool] +name = "Liquid" +category = "build" +homepage = "https://shopify.github.io/liquid" +docs = "https://shopify.github.io/liquid" +repo = "https://github.com/Shopify/liquid" +description = "Safe customer-facing template language" + +[detect] +dependencies = ["liquid"] +ecosystems = ["ruby"] + +[taxonomy] +role = ["library"] +function = ["templating"] +layer = ["backend"] + +[[security.sinks]] +symbol = "Liquid::Template.parse" +threat = "ssti" +cwe = "CWE-1336" +note = "Designed to be safe but custom tags/filters may not be" diff --git a/knowledge/ruby/nokogiri.toml b/knowledge/ruby/nokogiri.toml new file mode 100644 index 0000000..697f913 --- /dev/null +++ b/knowledge/ruby/nokogiri.toml @@ -0,0 +1,33 @@ +[tool] +name = "Nokogiri" +category = "build" +homepage = "https://nokogiri.org" +docs = "https://nokogiri.org" +repo = "https://github.com/sparklemotion/nokogiri" +description = "XML and HTML parser" + +[detect] +dependencies = ["nokogiri"] +ecosystems = ["ruby"] + +[taxonomy] +role = ["library"] +function = ["parsing"] +layer = ["backend"] + +[[security.sinks]] +symbol = "Nokogiri::XML" +threat = "xxe" +cwe = "CWE-611" +note = "Pass NONET option to block; safe-ish defaults since 1.13" + +[[security.sinks]] +symbol = "Nokogiri::XML::Document.parse" +threat = "xxe" +cwe = "CWE-611" + +[[security.sinks]] +symbol = "Nokogiri::XSLT" +threat = "code_injection" +cwe = "CWE-94" +note = "XSLT extensions can call Ruby; CVE-2019-5477 class" diff --git a/knowledge/ruby/omniauth.toml b/knowledge/ruby/omniauth.toml new file mode 100644 index 0000000..8cd4dd1 --- /dev/null +++ b/knowledge/ruby/omniauth.toml @@ -0,0 +1,22 @@ +[tool] +name = "OmniAuth" +category = "build" +homepage = "https://github.com/omniauth/omniauth" +docs = "https://github.com/omniauth/omniauth" +repo = "https://github.com/omniauth/omniauth" +description = "Multi-provider authentication" + +[detect] +dependencies = ["omniauth"] +ecosystems = ["ruby"] + +[taxonomy] +role = ["library"] +function = ["authentication"] +layer = ["backend"] + +[[security.sinks]] +symbol = "request.env[\"omniauth.auth\"]" +threat = "auth_bypass" +cwe = "CWE-287" +note = "Trust only after CSRF protection; CVE-2015-9284" diff --git a/knowledge/ruby/ox.toml b/knowledge/ruby/ox.toml new file mode 100644 index 0000000..add2116 --- /dev/null +++ b/knowledge/ruby/ox.toml @@ -0,0 +1,28 @@ +[tool] +name = "Ox" +category = "build" +homepage = "https://github.com/ohler55/ox" +docs = "https://github.com/ohler55/ox" +repo = "https://github.com/ohler55/ox" +description = "Fast XML parser for Ruby" + +[detect] +dependencies = ["ox"] +ecosystems = ["ruby"] + +[taxonomy] +role = ["library"] +function = ["parsing"] +layer = ["backend"] + +[[security.sinks]] +symbol = "Ox.parse_obj" +threat = "deserialization" +cwe = "CWE-502" +note = "Object mode instantiates arbitrary classes" + +[[security.sinks]] +symbol = "Ox.load" +threat = "deserialization" +cwe = "CWE-502" +note = "With mode: :object" diff --git a/knowledge/ruby/rest-client-rb.toml b/knowledge/ruby/rest-client-rb.toml new file mode 100644 index 0000000..8de21e2 --- /dev/null +++ b/knowledge/ruby/rest-client-rb.toml @@ -0,0 +1,31 @@ +[tool] +name = "RestClient" +category = "build" +homepage = "https://github.com/rest-client/rest-client" +docs = "https://github.com/rest-client/rest-client" +repo = "https://github.com/rest-client/rest-client" +description = "Simple HTTP and REST client" + +[detect] +dependencies = ["rest-client"] +ecosystems = ["ruby"] + +[taxonomy] +role = ["library"] +function = ["http-client"] +layer = ["backend"] + +[[security.sinks]] +symbol = "RestClient.get" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "RestClient.post" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "RestClient::Request.execute" +threat = "ssrf" +cwe = "CWE-918" diff --git a/knowledge/ruby/shrine.toml b/knowledge/ruby/shrine.toml new file mode 100644 index 0000000..cc0a9d6 --- /dev/null +++ b/knowledge/ruby/shrine.toml @@ -0,0 +1,21 @@ +[tool] +name = "Shrine" +category = "build" +homepage = "https://shrinerb.com" +docs = "https://shrinerb.com" +repo = "https://github.com/shrinerb/shrine" +description = "File attachment toolkit" + +[detect] +dependencies = ["shrine"] +ecosystems = ["ruby"] + +[taxonomy] +role = ["library"] +function = ["file-management"] +layer = ["backend"] + +[[security.sinks]] +symbol = "original_filename" +threat = "path_traversal" +cwe = "CWE-22" diff --git a/knowledge/ruby/slim.toml b/knowledge/ruby/slim.toml new file mode 100644 index 0000000..c39b007 --- /dev/null +++ b/knowledge/ruby/slim.toml @@ -0,0 +1,27 @@ +[tool] +name = "Slim" +category = "build" +homepage = "https://slim-template.github.io" +docs = "https://slim-template.github.io" +repo = "https://github.com/slim-template/slim" +description = "Lightweight template engine" + +[detect] +dependencies = ["slim"] +ecosystems = ["ruby"] + +[taxonomy] +role = ["library"] +function = ["templating"] +layer = ["backend"] + +[[security.sinks]] +symbol = "==" +threat = "xss" +cwe = "CWE-79" +note = "Unescaped output; = is escaped" + +[[security.sinks]] +symbol = "Slim::Template.new" +threat = "ssti" +cwe = "CWE-1336" diff --git a/knowledge/rust/reqwest.toml b/knowledge/rust/reqwest.toml new file mode 100644 index 0000000..1c96b02 --- /dev/null +++ b/knowledge/rust/reqwest.toml @@ -0,0 +1,31 @@ +[tool] +name = "reqwest" +category = "build" +homepage = "https://docs.rs/reqwest" +docs = "https://docs.rs/reqwest" +repo = "https://github.com/seanmonstar/reqwest" +description = "HTTP client for Rust" + +[detect] +dependencies = ["reqwest"] +ecosystems = ["rust"] + +[taxonomy] +role = ["library"] +function = ["http-client"] +layer = ["backend"] + +[[security.sinks]] +symbol = "reqwest::get" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "Client::get" +threat = "ssrf" +cwe = "CWE-918" + +[[security.sinks]] +symbol = "Client::post" +threat = "ssrf" +cwe = "CWE-918" diff --git a/testdata/python-project/pyproject.toml b/testdata/python-project/pyproject.toml index 5e75bbb..9ee34ad 100644 --- a/testdata/python-project/pyproject.toml +++ b/testdata/python-project/pyproject.toml @@ -1,6 +1,7 @@ [project] name = "test-project" version = "0.1.0" +dependencies = ["requests", "jinja2"] [tool.ruff] line-length = 88