diff --git a/cpp/ql/src/Microsoft/Likely Bugs/Likely Typos/BadWchar.cpp b/cpp/ql/src/Microsoft/Likely Bugs/Likely Typos/BadWchar.cpp
new file mode 100644
index 000000000000..3e62eed01b76
--- /dev/null
+++ b/cpp/ql/src/Microsoft/Likely Bugs/Likely Typos/BadWchar.cpp
@@ -0,0 +1,16 @@
+// Query should catch invalidWchar1 and invalidWchar2 but not semiValidWchar and validWchar
+const WCHAR invalidWchar3[] = {
+ L'C', L'P', L'R', L'O', L'G', L'R', L'A', L'M', L' ', L'1', L'.', L'0',
+ 'L\0'};
+
+const WCHAR invalidWchar2[] = {
+ L'C', L'P', L'R', L'O', L'G', L'R', L'A', L'M', L' ', L'1', L'.', L'0',
+ 'LZ'};
+
+const WCHAR semiValidWchar[] = {
+ L'C', L'P', L'R', L'O', L'G', L'R', L'A', L'M', L' ', L'1', L'.', L'0',
+ L'L\0'};
+
+const WCHAR validWchar[] = {
+ L'C', L'P', L'R', L'O', L'G', L'R', L'A', L'M', L' ', L'1', L'.', L'0',
+ L'\0'};
\ No newline at end of file
diff --git a/cpp/ql/src/Microsoft/Likely Bugs/Likely Typos/BadWchar.qhelp b/cpp/ql/src/Microsoft/Likely Bugs/Likely Typos/BadWchar.qhelp
new file mode 100644
index 000000000000..e9ec3cc902ec
--- /dev/null
+++ b/cpp/ql/src/Microsoft/Likely Bugs/Likely Typos/BadWchar.qhelp
@@ -0,0 +1,15 @@
+
+
+
+
This rule finds wide character that is initialized wrong due to a typo.
+
+
+
+
The wide character should be initialized with the L prefix. If L is accidentally included
+ inside the character literal, it should be moved outside to be a prefix.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cpp/ql/src/Microsoft/Likely Bugs/Likely Typos/BadWchar.ql b/cpp/ql/src/Microsoft/Likely Bugs/Likely Typos/BadWchar.ql
new file mode 100644
index 000000000000..780b59f3444c
--- /dev/null
+++ b/cpp/ql/src/Microsoft/Likely Bugs/Likely Typos/BadWchar.ql
@@ -0,0 +1,40 @@
+/**
+ * @id cpp/microsoft/public/typo/bad-wchar
+ * @name Initialization of bad wide char
+ * @description wchar_t should be initialized with L prefix but might be initialized inside single quote. E.g. 'L\0' instead of L'\0'
+ * @kind problem
+ * @problem.severity error
+ * @precision high
+ * @tags security
+ */
+
+import cpp
+
+/**
+ * Check where wchar_t is initalized wrong.
+ * E.g. wchar_t a = 'LZ' (bad) instead of L'Z' (good)
+ */
+predicate badWchar(CharLiteral cl) {
+ cl.getActualType().hasName("wchar_t") and
+ cl.getValueText().regexpMatch("'L.+'") // wchar_t getValueText() generally looks like L'Z' or 'L\0'. but if it is 'LZ' or 'L\0', this might be bad
+}
+
+/**
+ * when codeql can't figure out what underlying type it is, it will default to int. Scenarios unique_ptr, it seems to have hard time figuring out...
+ * we can check for others like 'LZ' or 'LA' but you will get alot of false positive since there can be enum :int with 'LZ' field etc
+ * E.g. unique_ptr('L\0'). If codeql couldnt figureout what unique_ptr is pointing to it will set it int.
+ */
+predicate wcharNullOnNonWchar(CharLiteral cl) {
+ cl.getValue().toInt() = 19456 // 19456 (0x4c00) is 'L\0'
+}
+
+from CharLiteral cl, string msg
+where
+ (
+ wcharNullOnNonWchar(cl) or
+ badWchar(cl)
+ ) and
+ msg =
+ " Varible of type wchar_t maybe have been initialized with a typo. " + cl.getValueText() +
+ " should be L'" + cl.getValueText().substring(2, cl.getValueText().length())
+select cl, "$@: " + msg, cl, cl.getValueText()
diff --git a/cpp/ql/test/query-tests/Microsoft/Likely Bugs/Likely Typos/BadWchar/BadWchar.expected b/cpp/ql/test/query-tests/Microsoft/Likely Bugs/Likely Typos/BadWchar/BadWchar.expected
new file mode 100644
index 000000000000..3d22fe3ae8fe
--- /dev/null
+++ b/cpp/ql/test/query-tests/Microsoft/Likely Bugs/Likely Typos/BadWchar/BadWchar.expected
@@ -0,0 +1,2 @@
+| test.cpp:8:9:8:13 | 19456 | $@: Varible of type wchar_t maybe have been initialized with a typo. 'L\\0' should be L'\\0' | test.cpp:8:9:8:13 | 19456 | 'L\\0' |
+| test.cpp:12:9:12:12 | 19546 | $@: Varible of type wchar_t maybe have been initialized with a typo. 'LZ' should be L'Z' | test.cpp:12:9:12:12 | 19546 | 'LZ' |
diff --git a/cpp/ql/test/query-tests/Microsoft/Likely Bugs/Likely Typos/BadWchar/BadWchar.qlref b/cpp/ql/test/query-tests/Microsoft/Likely Bugs/Likely Typos/BadWchar/BadWchar.qlref
new file mode 100644
index 000000000000..4c0f772abec5
--- /dev/null
+++ b/cpp/ql/test/query-tests/Microsoft/Likely Bugs/Likely Typos/BadWchar/BadWchar.qlref
@@ -0,0 +1 @@
+Microsoft/Likely Bugs/Likely Typos/BadWchar.ql
\ No newline at end of file
diff --git a/cpp/ql/test/query-tests/Microsoft/Likely Bugs/Likely Typos/BadWchar/test.cpp b/cpp/ql/test/query-tests/Microsoft/Likely Bugs/Likely Typos/BadWchar/test.cpp
new file mode 100644
index 000000000000..d4f5dee31c4b
--- /dev/null
+++ b/cpp/ql/test/query-tests/Microsoft/Likely Bugs/Likely Typos/BadWchar/test.cpp
@@ -0,0 +1,24 @@
+// Query should catch invalidWchar1 and invalidWchar2 in invalidWcharTest function but not semiValidWchar and validWchar in validWcharTest function
+typedef wchar_t WCHAR;
+
+void invalidWcharTest()
+{
+ const WCHAR invalidWchar3[] = {
+ L'C', L'P', L'R', L'O', L'G', L'R', L'A', L'M', L' ', L'1', L'.', L'0',
+ 'L\0'}; // 'L\0' should be L'\0'
+
+ const WCHAR invalidWchar2[] = {
+ L'C', L'P', L'R', L'O', L'G', L'R', L'A', L'M', L' ', L'1', L'.', L'0',
+ 'LZ'}; // 'LZ' should be L'Z'
+}
+
+void validWcharTest()
+{
+ const WCHAR semiValidWchar[] = {
+ L'C', L'P', L'R', L'O', L'G', L'R', L'A', L'M', L' ', L'1', L'.', L'0',
+ L'L\0'};
+
+ const WCHAR validWchar[] = {
+ L'C', L'P', L'R', L'O', L'G', L'R', L'A', L'M', L' ', L'1', L'.', L'0',
+ L'\0'};
+}
\ No newline at end of file