diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/AndroidManifest.xml b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/AndroidManifest.xml
new file mode 100644
index 00000000000..da5cdabce67
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/AndroidManifest.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/Test.java b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/Test.java
new file mode 100644
index 00000000000..ed141d80521
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/Test.java
@@ -0,0 +1,12 @@
+import java.net.URL;
+import java.net.URLConnection;
+
+class Test{
+ URLConnection test1() throws Exception {
+ return new URL("https://good.example.com").openConnection();
+ }
+
+ URLConnection test2() throws Exception {
+ return new URL("https://bad.example.com").openConnection(); // $hasUntrustedResult
+ }
+}
\ No newline at end of file
diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/options b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/options
new file mode 100644
index 00000000000..7d1644b057b
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/options
@@ -0,0 +1 @@
+// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/google-android-9.0.0
\ No newline at end of file
diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/res/xml/NetworkSecurityConfig.xml b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/res/xml/NetworkSecurityConfig.xml
new file mode 100644
index 00000000000..e2810ff7e1a
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/res/xml/NetworkSecurityConfig.xml
@@ -0,0 +1,9 @@
+
+
+
+ good.example.com
+
+ ...
+
+
+
\ No newline at end of file
diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/test.expected b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/test.expected
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/test.ql b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/test.ql
new file mode 100644
index 00000000000..22238774af5
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test1/test.ql
@@ -0,0 +1,23 @@
+import java
+import TestUtilities.InlineExpectationsTest
+import semmle.code.java.security.AndroidCertificatePinningQuery
+
+class Test extends InlineExpectationsTest {
+ Test() { this = "AndroidMissingCertificatePinningTest" }
+
+ override string getARelevantTag() { result = ["hasNoTrustedResult", "hasUntrustedResult"] }
+
+ override predicate hasActualResult(Location loc, string el, string tag, string value) {
+ exists(DataFlow::Node node |
+ missingPinning(node) and
+ loc = node.getLocation() and
+ el = node.toString() and
+ value = "" and
+ (
+ if exists(string x | trustedDomain(x))
+ then tag = "hasUntrustedResult"
+ else tag = "hasNoTrustedResult"
+ )
+ )
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/AndroidManifest.xml b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/AndroidManifest.xml
new file mode 100644
index 00000000000..da5cdabce67
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/AndroidManifest.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/Test.java b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/Test.java
new file mode 100644
index 00000000000..9f68c503b46
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/Test.java
@@ -0,0 +1,8 @@
+import java.net.URL;
+import java.net.URLConnection;
+
+class Test{
+ URLConnection test2() throws Exception {
+ return new URL("https://example.com").openConnection(); // $hasNoTrustedResult
+ }
+}
\ No newline at end of file
diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/options b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/options
new file mode 100644
index 00000000000..7d1644b057b
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/options
@@ -0,0 +1 @@
+// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/google-android-9.0.0
\ No newline at end of file
diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/res/xml/NetworkSecurityConfig.xml b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/res/xml/NetworkSecurityConfig.xml
new file mode 100644
index 00000000000..3fd128a05a2
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/res/xml/NetworkSecurityConfig.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/test.expected b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/test.expected
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/test.ql b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/test.ql
new file mode 100644
index 00000000000..22238774af5
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning_/Test2/test.ql
@@ -0,0 +1,23 @@
+import java
+import TestUtilities.InlineExpectationsTest
+import semmle.code.java.security.AndroidCertificatePinningQuery
+
+class Test extends InlineExpectationsTest {
+ Test() { this = "AndroidMissingCertificatePinningTest" }
+
+ override string getARelevantTag() { result = ["hasNoTrustedResult", "hasUntrustedResult"] }
+
+ override predicate hasActualResult(Location loc, string el, string tag, string value) {
+ exists(DataFlow::Node node |
+ missingPinning(node) and
+ loc = node.getLocation() and
+ el = node.toString() and
+ value = "" and
+ (
+ if exists(string x | trustedDomain(x))
+ then tag = "hasUntrustedResult"
+ else tag = "hasNoTrustedResult"
+ )
+ )
+ }
+}