diff --git a/rules/cpp/return-c-str-c.yml b/rules/cpp/return-c-str-c.yml new file mode 100644 index 00000000..b6f2ea92 --- /dev/null +++ b/rules/cpp/return-c-str-c.yml @@ -0,0 +1,27 @@ +id: return-c-str-cpp +language: cpp +severity: warning +message: >- + "`$FUNC` returns a pointer to the memory owned by `$STR`. This pointer + is invalid after `$STR` goes out of scope, which can trigger a use after + free." +note: >- + [CWE-416] Use After Free + [REFERENCES] + - https://wiki.sei.cmu.edu/confluence/display/c/DCL30-C.+Declare+objects+with+appropriate+storage+durations + - https://wiki.sei.cmu.edu/confluence/display/cplusplus/EXP54-CPP.+Do+not+access+an+object+outside+of+its+lifetime + +rule: + kind: return_statement + any: + - pattern: return basic_string<$TYPE>($$$).$METHOD(); + - pattern: return std::basic_string<$TYPE>($$$).$METHOD(); + - pattern: return string($$$).$METHOD(); + - pattern: return std::string($$$).$METHOD(); + - pattern: return wstring($$$).$METHOD(); + - pattern: return std::wstring($$$).$METHOD(); + +constraints: + METHOD: + regex: ^(c_str|data)$ + diff --git a/rules/go/security/avoid-bind-to-all-interfaces-go.yml b/rules/go/security/avoid-bind-to-all-interfaces-go.yml new file mode 100644 index 00000000..9ac2e644 --- /dev/null +++ b/rules/go/security/avoid-bind-to-all-interfaces-go.yml @@ -0,0 +1,30 @@ +id: avoid-bind-to-all-interfaces-go +language: go +severity: warning +message: >- + "Detected a network listener listening on 0.0.0.0 or an empty string. + This could unexpectedly expose the server publicly as it binds to all + available interfaces. Instead, specify another IP address that is not + 0.0.0.0 nor the empty string." +note: >- + [CWE-200] Exposure of Sensitive Information to an Unauthorized Actor + [REFERENCES] + - https://owasp.org/Top10/A01_2021-Broken_Access_Control + +rule: + not: + has: + stopBy: end + kind: ERROR + any: + - pattern: tls.Listen($NETWORK, $IP $$$) + - pattern: net.Listen($NETWORK, $IP $$$) + +constraints: + IP: + any: + - kind: interpreted_string_literal + regex: ^"0.0.0.0:.*"$|^":.*"$|^'0.0.0.0:.*'$|^':.*'$ + - kind: raw_string_literal + regex: ^`0.0.0.0:.*`$|^`:.*`$ + diff --git a/tests/__snapshots__/avoid-bind-to-all-interfaces-go-snapshot.yml b/tests/__snapshots__/avoid-bind-to-all-interfaces-go-snapshot.yml new file mode 100644 index 00000000..7c22130f --- /dev/null +++ b/tests/__snapshots__/avoid-bind-to-all-interfaces-go-snapshot.yml @@ -0,0 +1,16 @@ +id: avoid-bind-to-all-interfaces-go +snapshots: + ? | + l, err := net.Listen("tcp", "0.0.0.0:2000") + : labels: + - source: net.Listen("tcp", "0.0.0.0:2000") + style: primary + start: 10 + end: 43 + ? | + l, err := net.Listen("tcp", ":2000") + : labels: + - source: net.Listen("tcp", ":2000") + style: primary + start: 10 + end: 36 diff --git a/tests/__snapshots__/return-c-str-cpp-snapshot.yml b/tests/__snapshots__/return-c-str-cpp-snapshot.yml new file mode 100644 index 00000000..56d09ba6 --- /dev/null +++ b/tests/__snapshots__/return-c-str-cpp-snapshot.yml @@ -0,0 +1,29 @@ +id: return-c-str-cpp +snapshots: + ? | + char *return_basic_string_directly() { + return std::basic_string("foo").c_str(); + } + : labels: + - source: return std::basic_string("foo").c_str(); + style: primary + start: 41 + end: 87 + ? | + char *return_data_directly() { + return std::string("foo").data(); + } + : labels: + - source: return std::string("foo").data(); + style: primary + start: 33 + end: 66 + ? | + char *return_directly() { + return string("foo").c_str(); + } + : labels: + - source: return string("foo").c_str(); + style: primary + start: 28 + end: 57 diff --git a/tests/__snapshots__/sizeof-this-cpp-snapshot.yml b/tests/__snapshots__/sizeof-this-cpp-snapshot.yml index 9875c137..16d1c43f 100644 --- a/tests/__snapshots__/sizeof-this-cpp-snapshot.yml +++ b/tests/__snapshots__/sizeof-this-cpp-snapshot.yml @@ -1,2 +1,13 @@ id: sizeof-this-cpp -snapshots: {} +snapshots: + ? | + return sizeof(this); + : labels: + - source: sizeof(this) + style: primary + start: 7 + end: 19 + - source: this + style: secondary + start: 14 + end: 18 diff --git a/tests/cpp/return-c-str-cpp-test.yml b/tests/cpp/return-c-str-cpp-test.yml new file mode 100644 index 00000000..4aefc3d1 --- /dev/null +++ b/tests/cpp/return-c-str-cpp-test.yml @@ -0,0 +1,24 @@ +id: return-c-str-cpp +valid: + - | + std::string return_directly() { + // ok: return-c-str + return std::string("foo"); + } +invalid: + - | + char *return_namespace_directly() { + return std::string("foo").c_str(); + } + - | + char *return_directly() { + return string("foo").c_str(); + } + - | + char *return_basic_string_directly() { + return std::basic_string("foo").c_str(); + } + - | + char *return_data_directly() { + return std::string("foo").data(); + } diff --git a/tests/go/avoid-bind-to-all-interfaces-go-test.yml b/tests/go/avoid-bind-to-all-interfaces-go-test.yml new file mode 100644 index 00000000..4aebe122 --- /dev/null +++ b/tests/go/avoid-bind-to-all-interfaces-go-test.yml @@ -0,0 +1,9 @@ +id: avoid-bind-to-all-interfaces-go +valid: + - | + l, err := net.Listen("tcp", "192.168.1.101:2000") +invalid: + - | + l, err := net.Listen("tcp", "0.0.0.0:2000") + - | + l, err := net.Listen("tcp", ":2000")