├── README.md ├── dockerfile ├── custom-base-image.yaml ├── last-user-is-root.yaml ├── missing-healthcheck.yaml ├── missing-stage-build.yaml └── missing-user.yaml ├── go ├── go.common.audit.go-routine-on-loop-iterator-variables.yaml ├── go.gorilla.security.audit.websocket-checkorigin-missing.yaml └── go.lang.security.ldap-injection.ldap-injection.yaml ├── java ├── VulnerableLog4jExampleHandler.java ├── java.log4j.security.import.yaml ├── jaxb-xxe.java ├── jaxb-xxe.yaml ├── x-forwarded-for-control.java └── x-forwarded-for-control.yaml └── php └── lang ├── laravel └── security │ ├── getclientmimetype-used.yaml │ ├── insecure-deserialization.yaml │ ├── simple-sql-injection.yaml │ └── unrestricted-file-upload.yaml └── security └── insecure-deserialization.yaml /README.md: -------------------------------------------------------------------------------- 1 | Some custom semgrep rules used in Kondukto 2 | 3 | 4 | 5 | ### What is Kondukto? 6 | [Kondukto](https://kondukto.io) is an Application Security Testing orchestration and correlation platform that helps you centralize and automate your entire AppSec related vulnerability management process. Providing an interface where security health of applications can be continuously monitored, and a command line interface where your AppSec operations can be integrated into DevOps pipelines, Kondukto lets you manage your AppSec processes automatically with ease. 7 | 8 | 9 | 10 | ### What is Semgrep? 11 | [Semgrep](https://r2c.dev/) is a multi-language, highly customizable SAST tool for easily detecting and preventing bugs or anti-patterns in your codebase. 12 | 13 | 14 | -------------------------------------------------------------------------------- /dockerfile/custom-base-image.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: use-distroless-base-image 3 | languages: 4 | - dockerfile 5 | message: >- 6 | Distroless base image not found. Please use `gcr.io/distroless/static-debian10` as a base image. 7 | severity: ERROR 8 | metadata: 9 | category: security 10 | technology: 11 | - dockerfile 12 | patterns: 13 | - pattern-regex: FR\w+\s[a-zA-Z0-9]\w+\:+\w+ 14 | - pattern-not: FROM gcr.io/distroless/static-debian10 15 | - pattern-not-regex: \s*\#.* 16 | - pattern-not-inside: FROM $IMAGE:$TAG as builder 17 | paths: 18 | exclude: 19 | - "./vendor/*" 20 | -------------------------------------------------------------------------------- /dockerfile/last-user-is-root.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: last-user-is-root 3 | languages: 4 | - dockerfile 5 | message: >- 6 | The last user in the container is 'root'. This is a security 7 | hazard because if an attacker gains control of the container 8 | they will have root access. Switch back to another user after 9 | running commands as 'root'. 10 | severity: ERROR 11 | metadata: 12 | source-rule-url: https://github.com/hadolint/hadolint/wiki/DL3002 13 | references: 14 | - https://github.com/hadolint/hadolint/wiki/DL3002 15 | category: security 16 | technology: 17 | - dockerfile 18 | confidence: MEDIUM 19 | patterns: 20 | - pattern: USER root 21 | - pattern-not-inside: | 22 | USER root 23 | ... 24 | USER $USER 25 | paths: 26 | exclude: 27 | - "./vendor/*" 28 | -------------------------------------------------------------------------------- /dockerfile/missing-healthcheck.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: missing-healthcheck 3 | languages: 4 | - dockerfile 5 | message: >- 6 | Missing HEALTHCHECK instruction. 7 | severity: INFO 8 | metadata: 9 | category: best-practice 10 | technology: 11 | - dockerfile 12 | patterns: 13 | - pattern: | 14 | FROM gcr.io/distroless/static-debian10 15 | ... 16 | - pattern-not-inside: | 17 | FROM gcr.io/distroless/static-debian10 18 | ... 19 | HEALTHCHECK $F 20 | ... 21 | paths: 22 | exclude: 23 | - "./vendor/*" 24 | -------------------------------------------------------------------------------- /dockerfile/missing-stage-build.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: stage-build 3 | languages: 4 | - dockerfile 5 | message: >- 6 | Missing multistage builds. 7 | severity: INFO 8 | metadata: 9 | category: best-practice 10 | technology: 11 | - dockerfile 12 | patterns: 13 | - pattern: | 14 | FROM $STAGE AS builder 15 | ... 16 | - pattern-not-inside: | 17 | FROM $STAGE AS builder 18 | ... 19 | FROM $IMAGE 20 | ... 21 | paths: 22 | exclude: 23 | - "./vendor/*" 24 | 25 | -------------------------------------------------------------------------------- /dockerfile/missing-user.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: missing-user 3 | languages: 4 | - dockerfile 5 | message: 6 | By not specifying a USER, a program in the container may run as 'root'. This is a security hazard. If an attacker 7 | can control a process running as root, they may have control over the container. Ensure that the last USER in a Dockerfile 8 | is a USER other than 'root'. 9 | severity: ERROR 10 | metadata: 11 | category: security 12 | technology: 13 | - dockerfile 14 | confidence: MEDIUM 15 | patterns: 16 | - pattern-either: 17 | - pattern: CMD ... 18 | - pattern: ENTRYPOINT ... 19 | - pattern-not-inside: | 20 | USER $USER 21 | ... 22 | -------------------------------------------------------------------------------- /go/go.common.audit.go-routine-on-loop-iterator-variables.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: go.common.audit.go-routine-on-loop-iterator-variables 3 | metadata: 4 | references: 5 | - https://github.com/golang/go/wiki/CommonMistakes 6 | patterns: 7 | - pattern-inside: | 8 | func $FUNC(...) { 9 | ... 10 | } 11 | - pattern-either: 12 | - pattern: | 13 | for $X, $Y := range $LOOP { 14 | ... 15 | go func(...) { 16 | ... 17 | $VAR.$XFUNC($Y) 18 | ... 19 | }() 20 | } 21 | - pattern: | 22 | for $X, $Y := range $LOOP { 23 | ... 24 | go func(...) { 25 | $VAR.$XFUNC($Y) 26 | }() 27 | } 28 | - pattern: | 29 | for $X, $Y := range $LOOP { 30 | ... 31 | go func(...) { 32 | $VAR = $XFUNC($Y) 33 | }() 34 | } 35 | - pattern: | 36 | for $X, $Y := range $LOOP { 37 | ... 38 | go func(...) { 39 | ... 40 | $VAR = $Y 41 | ... 42 | }() 43 | } 44 | - pattern-not: | 45 | for $X, $Y := range $LOOP { 46 | ... 47 | go func(...) { 48 | ... 49 | }($Y) 50 | } 51 | message: "In the \"$LOOP\" iteration, \"$Y\" should be added as a parameter to the goroutine" 52 | fix: "go func($Y){...}($Y)" 53 | languages: [go] 54 | severity: INFO 55 | 56 | -------------------------------------------------------------------------------- /go/go.gorilla.security.audit.websocket-checkorigin-missing.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: go.gorilla.security.audit.websocket-checkorigin-missing 3 | metadata: 4 | cwe: 'CWE-352' 5 | owasp: 'A1: Injection' 6 | references: 7 | - https://christian-schneider.net/CrossSiteWebSocketHijacking.html 8 | patterns: 9 | - pattern-either: 10 | - pattern: | 11 | $X.Upgrade(...) 12 | - pattern: | 13 | $X.Upgrade(...) 14 | - pattern-not-inside: | 15 | func $HANDLER(...) { 16 | ... 17 | $X.CheckOrigin 18 | ... 19 | } 20 | message: | 21 | The 'Origin' header of the Websocket handshake request is not checked. 22 | This could lead to Cross-Site WebSocket Hijacking vulnerability (CSWSH). 23 | languages: [go] 24 | severity: WARNING 25 | 26 | -------------------------------------------------------------------------------- /go/go.lang.security.ldap-injection.ldap-injection.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: go.lang.security.ldap-injection.ldap-inection 3 | message: | 4 | Detected non-constant data passed into an LDAP query. If this data can be 5 | controlled by an external user, this is an LDAP injection. 6 | Ensure data passed to an LDAP query is not controllable; or properly sanitize 7 | the data. 8 | metadata: 9 | cwe: "CWE-90: Improper Neutralization of Special Elements used in an LDAP Query ('LDAP Injection')" 10 | owasp: 'A1: Injection' 11 | languages: [go] 12 | severity: WARNING 13 | patterns: 14 | - pattern-either: 15 | - pattern: | 16 | $FILTER := fmt.Sprintf(...) 17 | ... 18 | $Q,... := <... ldap.NewSearchRequest(..., $FILTER, ...) ...> 19 | - pattern: | 20 | $Q,... := <... ldap.NewSearchRequest(..., fmt.Sprintf(...), ...) ...> 21 | -------------------------------------------------------------------------------- /java/VulnerableLog4jExampleHandler.java: -------------------------------------------------------------------------------- 1 | import org.apache.logging.log4j.Logger; 2 | 3 | import java.io.*; 4 | import java.util.*; 5 | 6 | public class VulnerableLog4jExampleHandler implements HttpHandler { 7 | 8 | static Logger log = Logger.getLogger(VulnerableLog4jExampleHandler.class); 9 | 10 | public void handle(HttpExchange he) throws IOException { 11 | string userAgent = he.getRequestHeader("user-agent"); 12 | // ruleid: log4j-message-lookup-injection 13 | log.info("Request User Agent:" + userAgent); 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /java/java.log4j.security.import.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: log4j-message-lookup-injection 3 | patterns: 4 | - pattern-either: 5 | - pattern: | 6 | import org.apache.logging.log4j.$Y; 7 | message: | 8 | Possible Lookup injection into Log4j messages. 9 | languages: [java] 10 | severity: WARNING 11 | metadata: 12 | cwe: "CWE-74: Improper Neutralization of Special Elements in Output Used by a 13 | Downstream Component ('Injection')" 14 | owasp: "A1: Injection" 15 | source-rule-url: https://www.lunasec.io/docs/blog/log4j-zero-day/ 16 | references: 17 | - https://issues.apache.org/jira/browse/LOG4J2-3198 18 | - https://www.lunasec.io/docs/blog/log4j-zero-day/ 19 | - https://logging.apache.org/log4j/2.x/manual/lookups.html 20 | category: security 21 | technology: 22 | - java 23 | license: Commons Clause License Condition v1.0[LGPL-2.1-only] 24 | 25 | -------------------------------------------------------------------------------- /java/jaxb-xxe.java: -------------------------------------------------------------------------------- 1 | import java.io.File; 2 | import java.util.List; 3 | 4 | import javax.xml.bind.JAXBContext; 5 | import javax.xml.bind.JAXBException; 6 | import javax.xml.bind.Unmarshaller; 7 | 8 | public class XmlToObject { 9 | public static void main(String[] args) { 10 | 11 | try { 12 | 13 | File file = new File("question.xml"); 14 | 15 | SAXParserFactory spf = SAXParserFactory.newInstance(); 16 | //spf.setFeature("http://xml.org/sax/features/external-general-entities", false); 17 | //spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); 18 | //spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); 19 | 20 | JAXBContext jaxbContext = JAXBContext.newInstance(Question.class); 21 | 22 | Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); 23 | Question que= (Question) jaxbUnmarshaller.unmarshal(file); 24 | 25 | System.out.println(que.getId()+" "+que.getQuestionname()); 26 | System.out.println("Answers:"); 27 | List list=que.getAnswers(); 28 | for(Answer ans:list) 29 | System.out.println(ans.getId()+" "+ans.getAnswername()+" "+ans.getPostedby()); 30 | 31 | } catch (JAXBException e) { 32 | e.printStackTrace(); 33 | } 34 | 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /java/jaxb-xxe.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: XXE 3 | metadata: 4 | owasp: "A4: XXE" 5 | cwe: 'CWE-611' 6 | references: 7 | - https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html 8 | - https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.md 9 | patterns: 10 | - pattern-either: 11 | - pattern: | 12 | JAXBContext $JC = $W.newInstance($CLASS); 13 | ... 14 | Unmarshaller $JU = $JC.createUnmarshaller(); 15 | 16 | - pattern-not-inside: | 17 | $RETURNTYPE $METHOD(...) { 18 | ... 19 | $X.setFeature("http://xml.org/sax/features/external-general-entities", false); 20 | $X.setFeature("http://xml.org/sax/features/external-parameter-entities", false); 21 | $X.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); 22 | ... 23 | } 24 | 25 | message: | 26 | Generic XXE in `$JC`. The 'javax.xml.bind.Unmarshaller' parses XML and does not support any flags for disabling XXE, it's imperative 27 | to parse the untrusted XML through a configurable secure parser first, generate a source object as a result, and pass the 28 | source object to the Unmarshaller. 29 | languages: [java] 30 | severity: ERROR 31 | -------------------------------------------------------------------------------- /java/x-forwarded-for-control.java: -------------------------------------------------------------------------------- 1 | package servlets; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.PrintWriter; 6 | 7 | import javax.servlet.ServletException; 8 | import javax.servlet.http.HttpServlet; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import javax.servlet.http.HttpSession; 12 | 13 | import org.apache.commons.io.FilenameUtils; 14 | 15 | public class Cls extends HttpServlet 16 | { 17 | private static org.apache.log4j.Logger log = Logger.getLogger(Register.class); 18 | 19 | public void doPost(HttpServletRequest request, HttpServletResponse response) 20 | throws ServletException, IOException 21 | { 22 | // ruleid:httpservlet-path-traversal 23 | String image = request.getParameter("image"); 24 | File file = new File("static/images/", image); 25 | 26 | if (!file.exists()) { 27 | log.info(image + " could not be created."); 28 | response.sendError(); 29 | } 30 | 31 | response.sendRedirect("/index.html"); 32 | } 33 | 34 | public void ok(HttpServletRequest request, HttpServletResponse response) 35 | throws ServletException, IOException 36 | { 37 | // ok:httpservlet-path-traversal 38 | String image = request.getParameter("image"); 39 | File file = new File("static/images/", FilenameUtils.getName(image)); 40 | 41 | if (!file.exists()) { 42 | log.info(image + " could not be created."); 43 | response.sendError(); 44 | } 45 | 46 | response.sendRedirect("/index.html"); 47 | } 48 | 49 | public String getClientIp(HttpServletRequest req) { 50 | String remoteAddr = ""; 51 | if (req != null) { 52 | remoteAddr = req.getHeader("X-FORWARDED-FOR"); 53 | if (InetAddress.isInetAddress(remoteAddr)) { 54 | return 55 | } 56 | if (StringUtils.isEmpty(remoteAddr)) { 57 | remoteAddr = req.getRemoteAddr(); 58 | } 59 | } 60 | return remoteAddr; 61 | } 62 | } 63 | 64 | 65 | -------------------------------------------------------------------------------- /java/x-forwarded-for-control.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: x-forwarded-for 3 | metadata: 4 | cwe: 'CWE-20' 5 | owasp: 'A1: Injection' 6 | references: 7 | - https://en.wikipedia.org/wiki/X-Forwarded-For 8 | patterns: 9 | - pattern-inside: | 10 | $RETURNTYPE $FUNC (HttpServletRequest $REQ, ...) { 11 | ... 12 | } 13 | - pattern: 14 | $ADDR = $REQ.getHeader($HEADER); 15 | - metavariable-regex: 16 | metavariable: '$HEADER' 17 | regex: '.(X-FORWARDED-FOR|X-Forwarded-For|x-forwarded-for).' 18 | 19 | message: | 20 | The X-Forwarded-For (XFF) HTTP header field is a common method for identifying the originating 21 | IP address of a client connecting to a web server through an HTTP proxy or load balancer. Since this header 22 | is not set by server and can be easily spoofed by the client It may cause injection attacks if `$ADDR` 23 | is not filtered for properly. 24 | languages: [java] 25 | severity: WARNING 26 | -------------------------------------------------------------------------------- /php/lang/laravel/security/getclientmimetype-used.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: getclientmimetype-used 3 | patterns: 4 | - pattern: $X->file->getClientMimeType(); 5 | fix: $X->file->getMimeType(); 6 | message: | 7 | For a trusted mime type, use `getMimeType()` instead (which guesses the mime 8 | type based on the file content). 9 | metadata: 10 | cwe: 'CWE-434' 11 | owasp: 'A1: Injection' 12 | references: 13 | - https://github.com/laravel/framework/issues/29962 14 | languages: [php] 15 | severity: INFO 16 | -------------------------------------------------------------------------------- /php/lang/laravel/security/insecure-deserialization.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: insecure-deserialization 3 | metadata: 4 | cwe: 'CWE-502' 5 | owasp: 'A8: Insecure Deserialization' 6 | references: 7 | - https://cwe.mitre.org/data/definitions/915.html 8 | - https://owasp.org/www-project-top-ten/2017/A8_2017-Insecure_Deserialization 9 | - https://sucuri.net/guides/owasp-top-10-security-vulnerabilities-2020/ 10 | patterns: 11 | - pattern: $FUNC(...); 12 | - metavariable-regex: 13 | metavariable: '$FUNC' 14 | regex: "(unserialize)" 15 | 16 | message: | 17 | The software receives input from an upstream component that specifies multiple attributes, properties, or fields that are to be initialized or updated in an object, but it does not properly control which attributes can be modified. 18 | languages: [php] 19 | severity: ERROR 20 | -------------------------------------------------------------------------------- /php/lang/laravel/security/simple-sql-injection.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: simple-sql-injection 3 | patterns: 4 | - pattern-regex: '(.*orderByRaw(.*).*|DB::raw.)' 5 | message: | 6 | Without sufficient removal or quoting of SQL syntax in user-controllable inputs, 7 | the generated SQL query can cause those inputs to be interpreted as SQL instead 8 | of ordinary user data. This can be used to alter query logic to bypass security checks, 9 | or to insert additional statements that modify the back-end database, possibly 10 | including execution of system commands. 11 | metadata: 12 | cwe: 'CWE-89' 13 | owasp: 'A1: Injection' 14 | references: 15 | - https://cwe.mitre.org/data/definitions/89.html 16 | languages: [php] 17 | severity: ERROR 18 | 19 | -------------------------------------------------------------------------------- /php/lang/laravel/security/unrestricted-file-upload.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: unrestricted-file-upload 3 | metadata: 4 | cwe: 'CWE-434' 5 | owasp: 'A1: Injection' 6 | references: 7 | - https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload 8 | patterns: 9 | - pattern-either: 10 | - pattern: | 11 | $FUNC($X,...); 12 | ... 13 | $R = $E->putFileAs(..., $X,...); 14 | ... 15 | - pattern: | 16 | $Y = $X->file(...); 17 | ... 18 | $R->putFileAs(..., $Y,...); 19 | 20 | 21 | message: | 22 | `$X` is saved without proper sanitization which could lead the client to uploading malicious 23 | file(s) to the server. 24 | languages: [php] 25 | severity: WARNING 26 | -------------------------------------------------------------------------------- /php/lang/security/insecure-deserialization.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: insecure-deserialization 3 | metadata: 4 | cwe: 'CWE-502' 5 | owasp: 'A8: Insecure Deserialization' 6 | references: 7 | - https://cwe.mitre.org/data/definitions/915.html 8 | - https://owasp.org/www-project-top-ten/2017/A8_2017-Insecure_Deserialization 9 | - https://sucuri.net/guides/owasp-top-10-security-vulnerabilities-2020/ 10 | patterns: 11 | - pattern: $FUNC(...); 12 | - metavariable-regex: 13 | metavariable: '$FUNC' 14 | regex: "(unserialize)" 15 | 16 | message: | 17 | The software receives input from an upstream component that specifies multiple attributes, properties, or fields that are to be initialized or updated in an object, but it does not properly control which attributes can be modified. 18 | languages: [php] 19 | severity: ERROR 20 | --------------------------------------------------------------------------------