From c2c65f694a7953b4beeaeb52ae6973c7db50fbae Mon Sep 17 00:00:00 2001 From: lucasan1 <70696858+lucasan1@users.noreply.github.com> Date: Tue, 3 Sep 2024 10:42:55 +0200 Subject: [PATCH 1/5] Added Onfido API token detection to recognize this type of secrets (#3463) --- .../detected-onfido-live-api-token.txt | 8 ++++++++ .../detected-onfido-live-api-token.yaml | 20 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 generic/secrets/security/detected-onfido-live-api-token.txt create mode 100644 generic/secrets/security/detected-onfido-live-api-token.yaml diff --git a/generic/secrets/security/detected-onfido-live-api-token.txt b/generic/secrets/security/detected-onfido-live-api-token.txt new file mode 100644 index 0000000000..e5df356ef3 --- /dev/null +++ b/generic/secrets/security/detected-onfido-live-api-token.txt @@ -0,0 +1,8 @@ +# ruleid: detected-onfido-live-api-token +api_live.abc123ABC-_.abc123ABC-_abc123ABC-_abc123ABC- + +# ruleid: detected-onfido-live-api-token +api_live_ca.abc123ABC-_.abc123ABC-_abc123ABC-_abc123ABC- + +# ruleid: detected-onfido-live-api-token +api_live_us.abc123ABC-_.abc123ABC-_abc123ABC-_abc123ABC- diff --git a/generic/secrets/security/detected-onfido-live-api-token.yaml b/generic/secrets/security/detected-onfido-live-api-token.yaml new file mode 100644 index 0000000000..be579fa82c --- /dev/null +++ b/generic/secrets/security/detected-onfido-live-api-token.yaml @@ -0,0 +1,20 @@ +rules: +- id: detected-onfido-live-api-token + pattern-regex: (?:api_live(?:_[a-zA-Z]{2})?\.[a-zA-Z0-9-_]{11}\.[-_a-zA-Z0-9]{32}) + languages: [regex] + message: Onfido live API Token detected + severity: ERROR + metadata: + cwe: + - 'CWE-798: Use of Hard-coded Credentials' + category: security + technology: + - secrets + - onfido + confidence: HIGH + references: + - https://documentation.onfido.com/api/latest/#api-tokens + subcategory: + - audit + likelihood: HIGH + impact: HIGH \ No newline at end of file From b3fd95ae5bb39a78001e7861b725c3c8770582a5 Mon Sep 17 00:00:00 2001 From: Sjoerd Langkemper Date: Tue, 3 Sep 2024 10:48:07 +0200 Subject: [PATCH 2/5] PHP tainted-callable (#3464) A callable is the name of a function, or an array with a class/object and a method. Basing these on user input makes it possible to call arbitrary functions. Co-authored-by: Pieter De Cremer (Semgrep) --- .../security/injection/tainted-callable.php | 12 ++ .../security/injection/tainted-callable.yaml | 115 ++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 php/lang/security/injection/tainted-callable.php create mode 100644 php/lang/security/injection/tainted-callable.yaml diff --git a/php/lang/security/injection/tainted-callable.php b/php/lang/security/injection/tainted-callable.php new file mode 100644 index 0000000000..9bd6fa095d --- /dev/null +++ b/php/lang/security/injection/tainted-callable.php @@ -0,0 +1,12 @@ +- + Callable based on user input risks remote code execution. + metadata: + technology: + - php + category: security + cwe: + - "CWE-94: Improper Control of Generation of Code ('Code Injection')" + owasp: + - A03:2021 - Injection + references: + - https://www.php.net/manual/en/language.types.callable.php + subcategory: + - vuln + impact: HIGH + likelihood: MEDIUM + confidence: MEDIUM + languages: [php] + mode: taint + pattern-sources: + - patterns: + - pattern-either: + - pattern: $_GET + - pattern: $_POST + - pattern: $_COOKIE + - pattern: $_REQUEST + - pattern: file_get_contents('php://input') + pattern-sinks: + - patterns: + - pattern: $CALLABLE + - pattern-either: + - pattern-inside: $ARRAYITERATOR->uasort($CALLABLE) + - pattern-inside: $ARRAYITERATOR->uksort($CALLABLE) + - pattern-inside: $EVENTHTTP->setCallback($CALLABLE, ...) + - pattern-inside: $EVENTHTTPCONNECTION->setCloseCallback($CALLABLE, ...) + - pattern-inside: $EVLOOP->fork($CALLABLE, ...) + - pattern-inside: $EVLOOP->idle($CALLABLE, ...) + - pattern-inside: $EVLOOP->prepare($CALLABLE, ...) + - pattern-inside: $EVWATCHER->setCallback($CALLABLE) + - pattern-inside: $GEARMANCLIENT->setClientCallback($CALLABLE) + - pattern-inside: $GEARMANCLIENT->setCompleteCallback($CALLABLE) + - pattern-inside: $GEARMANCLIENT->setCreatedCallback($CALLABLE) + - pattern-inside: $GEARMANCLIENT->setDataCallback($CALLABLE) + - pattern-inside: $GEARMANCLIENT->setExceptionCallback($CALLABLE) + - pattern-inside: $GEARMANCLIENT->setFailCallback($CALLABLE) + - pattern-inside: $GEARMANCLIENT->setStatusCallback($CALLABLE) + - pattern-inside: $GEARMANCLIENT->setWarningCallback($CALLABLE) + - pattern-inside: $GEARMANCLIENT->setWorkloadCallback($CALLABLE) + - pattern-inside: $IMAGICK->setProgressMonitor($CALLABLE) + - pattern-inside: $OAUTHPROVIDER->consumerHandler($CALLABLE) + - pattern-inside: $OAUTHPROVIDER->tokenHandler($CALLABLE) + - pattern-inside: $PDO->sqliteCreateCollation($NAME, $CALLABLE) + - pattern-inside: $PDOSTATEMENT->fetchAll(PDO::FETCH_FUNC, $CALLABLE) + - pattern-inside: $SQLITE3->createCollation($NAME, $CALLABLE) + - pattern-inside: $SQLITE3->setAuthorizer($CALLABLE) + - pattern-inside: $ZIPARCHIVE->registerCancelCallback($CALLABLE) + - pattern-inside: $ZIPARCHIVE->registerProgressCallback($RATE, $CALLABLE) + - pattern-inside: $ZMQDEVICE->setIdleCallback($CALLABLE, ...) + - pattern-inside: $ZMQDEVICE->setTimerCallback($CALLABLE, ...) + - pattern-inside: apcu_entry($KEY, $CALLABLE, ...) + - pattern-inside: array_filter($ARRAY, $CALLABLE, ...) + - pattern-inside: array_map($CALLABLE, ...) + - pattern-inside: array_reduce($ARRAY, $CALLABLE, ...) + - pattern-inside: array_walk_recursive($ARRAY, $CALLABLE, ...) + - pattern-inside: array_walk($ARRAY, $CALLABLE, ...) + - pattern-inside: call_user_func_array($CALLABLE, ...) + - pattern-inside: call_user_func($CALLABLE, ...) + - pattern-inside: Closure::fromCallable($CALLABLE) + - pattern-inside: createCollation($NAME, $CALLABLE) + - pattern-inside: eio_grp($CALLABLE, ...) + - pattern-inside: eio_nop($PRI, $CALLABLE, ...) + - pattern-inside: eio_sync($PRI, $CALLABLE, ...) + - pattern-inside: EvPrepare::createStopped($CALLABLE, ...) + - pattern-inside: fann_set_callback($ANN, $CALLABLE) + - pattern-inside: fdf_enum_values($FDF_DOCUMENT, $CALLABLE, ...) + - pattern-inside: forward_static_call_array($CALLABLE, ...) + - pattern-inside: forward_static_call($CALLABLE, ...) + - pattern-inside: header_register_callback($CALLABLE) + - pattern-inside: ibase_set_event_handler($CALLABLE, ...) + - pattern-inside: IntlChar::enumCharTypes($CALLABLE) + - pattern-inside: iterator_apply($ITERATOR, $CALLABLE) + - pattern-inside: ldap_set_rebind_proc($LDAP, $CALLABLE) + - pattern-inside: libxml_set_external_entity_loader($CALLABLE, ...) + - pattern-inside: new CallbackFilterIterator($ITERATOR, $CALLABLE) + - pattern-inside: new EvCheck($CALLABLE, ...) + - pattern-inside: new EventHttpRequest($CALLABLE, ...) + - pattern-inside: new EvFork($CALLABLE, ...) + - pattern-inside: new EvIdle($CALLABLE, ...) + - pattern-inside: new Fiber($CALLABLE) + - pattern-inside: new Memcached($PERSISTENT_ID, $CALLABLE, ...) + - pattern-inside: new RecursiveCallbackFilterIterator($ITERATOR, $CALLABLE) + - pattern-inside: new Zookeeper($HOST, $CALLABLE, ...) + - pattern-inside: ob_start($CALLABLE, ...) + - pattern-inside: oci_register_taf_callback($CONNECTION, $CALLABLE) + - pattern-inside: readline_callback_handler_install($PROMPT, $CALLABLE) + - pattern-inside: readline_completion_function($CALLABLE) + - pattern-inside: register_shutdown_function($CALLABLE, ...) + - pattern-inside: register_tick_function($CALLABLE, ...) + - pattern-inside: rnp_ffi_set_pass_provider($FFI, $CALLABLE) + - pattern-inside: sapi_windows_set_ctrl_handler($CALLABLE, ...) + - pattern-inside: set_error_handler($CALLABLE, ...) + - pattern-inside: set_exception_handler($CALLABLE) + - pattern-inside: setAuthorizer($CALLABLE) + - pattern-inside: spl_autoload_register($CALLABLE, ...) + - pattern-inside: uasort($ARRAY, $CALLABLE) + - pattern-inside: uksort($ARRAY, $CALLABLE) + - pattern-inside: usort($ARRAY, $CALLABLE) + - pattern-inside: xml_set_character_data_handler($PARSER, $CALLABLE) + - pattern-inside: xml_set_default_handler($PARSER, $CALLABLE) + - pattern-inside: xml_set_element_handler($PARSER, $CALLABLE, $CALLABLE) + - pattern-inside: xml_set_notation_decl_handler($PARSER, $CALLABLE) + - pattern-inside: Yar_Concurrent_Client::loop($CALLABLE, ...) From f1f6dc5e1ad8ad671919ee686dd08b5189d0c92e Mon Sep 17 00:00:00 2001 From: Yoann Padioleau Date: Thu, 5 Sep 2024 12:32:41 +0200 Subject: [PATCH 3/5] chore: put ruleid annotation alone on its own line for tainted-sql-string.py (#3467) This is the only file doing that, so let's be consistent. It also helps osemgrep test which does not handle this case. This was mentioned in https://linear.app/semgrep/issue/SAF-1529/same-line-annotations-fail-when-running-semgrep-test-but-work-with test plan: make test --- .../security/injection/tainted-sql-string.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/python/django/security/injection/tainted-sql-string.py b/python/django/security/injection/tainted-sql-string.py index 0aaa70d7b8..b4ae971fa2 100644 --- a/python/django/security/injection/tainted-sql-string.py +++ b/python/django/security/injection/tainted-sql-string.py @@ -10,7 +10,8 @@ class Person(models.Model): ##### True Positives ######### def get_user_age1(request): user_name = request.POST.get("user_name") - user_age = Person.objects.raw( # ruleid: tainted-sql-string + user_age = Person.objects.raw( + # ruleid: tainted-sql-string "SELECT user_age FROM myapp_person where user_name = %s" % user_name ) html = "User Age %s." % user_age @@ -19,7 +20,8 @@ def get_user_age1(request): def get_user_age2(request): user_name = request.POST.get("user_name") - user_age = Person.objects.raw( # ruleid: tainted-sql-string + user_age = Person.objects.raw( + # ruleid: tainted-sql-string f"SELECT user_age FROM myapp_person where user_name = {user_name}" ) html = "User Age %s." % user_age @@ -28,7 +30,8 @@ def get_user_age2(request): def get_user_age3(request): user_name = request.POST.get("user_name") - user_age = Person.objects.raw( # ruleid: tainted-sql-string + user_age = Person.objects.raw( + # ruleid: tainted-sql-string "SELECT user_age FROM myapp_person where user_name = %s".format(user_name) ) html = "User Age %s." % user_age @@ -37,7 +40,8 @@ def get_user_age3(request): def get_user_age4(request): user_name = request.POST.get("user_name") - user_age = Person.objects.raw( # ruleid: tainted-sql-string + user_age = Person.objects.raw( + # ruleid: tainted-sql-string "SELECT user_age FROM myapp_person where user_name = " + user_name ) html = "User Age %s." % user_age @@ -63,7 +67,8 @@ def get_user_age6(request): def get_users1(request): client_id = request.headers.get("client_id") - users = Person.objects.raw( # ruleid: tainted-sql-string + users = Person.objects.raw( + # ruleid: tainted-sql-string "SELECT * FROM myapp_person where client_id = %s" % client_id ) html = "Users %s." % users @@ -72,7 +77,8 @@ def get_users1(request): def get_users2(request): client_id = request.headers.get("client_id") - users = Person.objects.raw( # ruleid: tainted-sql-string + users = Person.objects.raw( + # ruleid: tainted-sql-string f"SELECT * FROM myapp_person where client_id = {client_id}" ) html = "Users %s." % users From b7565680af1e01ff275be68dafd4ccd517a99a06 Mon Sep 17 00:00:00 2001 From: Yoann Padioleau Date: Wed, 18 Sep 2024 11:17:28 +0200 Subject: [PATCH 4/5] Be consistent with using .fixed.test.yaml not .test.fixed.yaml (#3471) test plan: make test --- ...s.test.fixed.yaml => no-fractional-cpu-limits.fixed.test.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename yaml/kubernetes/best-practice/{no-fractional-cpu-limits.test.fixed.yaml => no-fractional-cpu-limits.fixed.test.yaml} (100%) diff --git a/yaml/kubernetes/best-practice/no-fractional-cpu-limits.test.fixed.yaml b/yaml/kubernetes/best-practice/no-fractional-cpu-limits.fixed.test.yaml similarity index 100% rename from yaml/kubernetes/best-practice/no-fractional-cpu-limits.test.fixed.yaml rename to yaml/kubernetes/best-practice/no-fractional-cpu-limits.fixed.test.yaml From 6d1b466dae4fe7111b91b989e2896e1fe9a1a3b7 Mon Sep 17 00:00:00 2001 From: Sjoerd Langkemper Date: Thu, 19 Sep 2024 08:43:26 +0200 Subject: [PATCH 5/5] PHP tainted exec (#3468) * PHP tainted exec When user input is passed to a function that executes a shell command, without escaping. * Correct message string YAML operator Co-authored-by: Pieter De Cremer (Semgrep) --------- Co-authored-by: Pieter De Cremer (Semgrep) Co-authored-by: Lewis --- php/lang/security/injection/tainted-exec.php | 21 ++++++++ php/lang/security/injection/tainted-exec.yaml | 51 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 php/lang/security/injection/tainted-exec.php create mode 100644 php/lang/security/injection/tainted-exec.yaml diff --git a/php/lang/security/injection/tainted-exec.php b/php/lang/security/injection/tainted-exec.php new file mode 100644 index 0000000000..9f4c123250 --- /dev/null +++ b/php/lang/security/injection/tainted-exec.php @@ -0,0 +1,21 @@ +- + User input is passed to a function that executes a shell command. This can lead to remote code execution. + metadata: + cwe: + - "CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')" + category: security + technology: + - php + owasp: + - A03:2021 - Injection + references: + - https://owasp.org/Top10/A03_2021-Injection + subcategory: + - vuln + impact: HIGH + likelihood: MEDIUM + confidence: MEDIUM + mode: taint + pattern-sources: + - patterns: + - pattern-either: + - pattern: $_GET + - pattern: $_POST + - pattern: $_COOKIE + - pattern: $_REQUEST + - pattern: file_get_contents('php://input') + pattern-sanitizers: + - patterns: + - pattern-either: + - pattern: escapeshellcmd(...) + - pattern: escapeshellarg(...) + pattern-sinks: + - patterns: + - pattern-either: + - pattern: exec(...) + - pattern: system(...) + - pattern: passthru(...) + - patterns: + - pattern: proc_open(...) + - pattern-not: proc_open([...], ...) + - pattern: popen(...) + - pattern: expect_popen(...) + - pattern: shell_exec(...) + - pattern: | + `...` +