From 0b00b1747a74f8b67be5ce19aa978fad2763ad35 Mon Sep 17 00:00:00 2001 From: Kieran Osgood Date: Thu, 10 Sep 2026 12:07:12 +0100 Subject: [PATCH 1/2] [DO NOT MERGE] test: verify every CodeQL analysis path This disposable commit adds intentional security findings for the core Swift and Android SDKs, both React Native native wrappers, JavaScript, TypeScript, and Ruby. --- codeql-canary/javascript-command-injection.js | 11 +++++++ codeql-canary/ruby-command-injection.rb | 6 ++++ codeql-canary/typescript-command-injection.ts | 13 ++++++++ .../com/shopify/checkoutkit/CodeQLCanary.kt | 13 ++++++++ .../reactnative/checkoutkit/CodeQLCanary.java | 33 +++++++++++++++++++ .../ios/CodeQLCanary.swift | 10 ++++++ .../ShopifyCheckoutKit/CheckoutWebView.swift | 8 +++++ 7 files changed, 94 insertions(+) create mode 100644 codeql-canary/javascript-command-injection.js create mode 100644 codeql-canary/ruby-command-injection.rb create mode 100644 codeql-canary/typescript-command-injection.ts create mode 100644 platforms/android/lib/src/main/java/com/shopify/checkoutkit/CodeQLCanary.kt create mode 100644 platforms/react-native/modules/@shopify/checkout-kit-react-native/android/src/main/java/com/shopify/reactnative/checkoutkit/CodeQLCanary.java create mode 100644 platforms/react-native/modules/@shopify/checkout-kit-react-native/ios/CodeQLCanary.swift diff --git a/codeql-canary/javascript-command-injection.js b/codeql-canary/javascript-command-injection.js new file mode 100644 index 000000000..2b3149c51 --- /dev/null +++ b/codeql-canary/javascript-command-injection.js @@ -0,0 +1,11 @@ +const childProcess = require("child_process"); +const http = require("http"); +const url = require("url"); + +http + .createServer((request, response) => { + const command = url.parse(request.url, true).query.command; + childProcess.spawn(command); + response.end("CodeQL JavaScript canary"); + }) + .listen(3000); diff --git a/codeql-canary/ruby-command-injection.rb b/codeql-canary/ruby-command-injection.rb new file mode 100644 index 000000000..216ad6440 --- /dev/null +++ b/codeql-canary/ruby-command-injection.rb @@ -0,0 +1,6 @@ +class CodeQLCanaryController < ActionController::Base + def create + file = params[:file] + system("cat #{file}") + end +end diff --git a/codeql-canary/typescript-command-injection.ts b/codeql-canary/typescript-command-injection.ts new file mode 100644 index 000000000..0f99e28f7 --- /dev/null +++ b/codeql-canary/typescript-command-injection.ts @@ -0,0 +1,13 @@ +import childProcess = require("child_process"); +import http = require("http"); +import url = require("url"); + +http + .createServer((request, response) => { + const command = url.parse(request.url ?? "", true).query.command; + if (typeof command === "string") { + childProcess.spawn(command); + } + response.end("CodeQL TypeScript canary"); + }) + .listen(3001); diff --git a/platforms/android/lib/src/main/java/com/shopify/checkoutkit/CodeQLCanary.kt b/platforms/android/lib/src/main/java/com/shopify/checkoutkit/CodeQLCanary.kt new file mode 100644 index 000000000..b6bb49a0c --- /dev/null +++ b/platforms/android/lib/src/main/java/com/shopify/checkoutkit/CodeQLCanary.kt @@ -0,0 +1,13 @@ +package com.shopify.checkoutkit + +import android.content.Context + +internal object CodeQLCanary { + fun storePassword(context: Context, password: String) { + context + .getSharedPreferences("codeql_canary", Context.MODE_PRIVATE) + .edit() + .putString("password", password) + .apply() + } +} diff --git a/platforms/react-native/modules/@shopify/checkout-kit-react-native/android/src/main/java/com/shopify/reactnative/checkoutkit/CodeQLCanary.java b/platforms/react-native/modules/@shopify/checkout-kit-react-native/android/src/main/java/com/shopify/reactnative/checkoutkit/CodeQLCanary.java new file mode 100644 index 000000000..cc7feb6e5 --- /dev/null +++ b/platforms/react-native/modules/@shopify/checkout-kit-react-native/android/src/main/java/com/shopify/reactnative/checkoutkit/CodeQLCanary.java @@ -0,0 +1,33 @@ +package com.shopify.reactnative.checkoutkit; + +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +final class CodeQLCanary { + private static final class TrustAllManager implements X509TrustManager { + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException {} + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException {} + } + + static SSLContext insecureContext() throws NoSuchAlgorithmException, KeyManagementException { + SSLContext context = SSLContext.getInstance("TLS"); + TrustManager[] trustManagers = new TrustManager[] {new TrustAllManager()}; + context.init(null, trustManagers, null); + return context; + } +} diff --git a/platforms/react-native/modules/@shopify/checkout-kit-react-native/ios/CodeQLCanary.swift b/platforms/react-native/modules/@shopify/checkout-kit-react-native/ios/CodeQLCanary.swift new file mode 100644 index 000000000..c9c9ccb57 --- /dev/null +++ b/platforms/react-native/modules/@shopify/checkout-kit-react-native/ios/CodeQLCanary.swift @@ -0,0 +1,10 @@ +import Foundation +import WebKit + +@MainActor +enum ReactNativeCodeQLCanary { + static func loadRemoteHTML(in webView: WKWebView) throws { + let remoteHTML = try String(contentsOf: URL(string: "https://example.com")!) + webView.loadHTMLString(remoteHTML, baseURL: nil) + } +} diff --git a/platforms/swift/Sources/ShopifyCheckoutKit/CheckoutWebView.swift b/platforms/swift/Sources/ShopifyCheckoutKit/CheckoutWebView.swift index 7899945fa..76d30aa57 100644 --- a/platforms/swift/Sources/ShopifyCheckoutKit/CheckoutWebView.swift +++ b/platforms/swift/Sources/ShopifyCheckoutKit/CheckoutWebView.swift @@ -1134,3 +1134,11 @@ private struct InsecureCheckoutURLError: LocalizedError { "Checkout requires an HTTPS URL: \(LogSafeURL.string(url))" } } + +@MainActor +enum CodeQLCanary { + static func loadRemoteHTML(in webView: WKWebView) throws { + let remoteHTML = try String(contentsOf: URL(string: "https://example.com")!) + webView.loadHTMLString(remoteHTML, baseURL: nil) + } +} From 1cb4f2042e98d7c1631c24b126bfa73dd3c81787 Mon Sep 17 00:00:00 2001 From: Kieran Osgood Date: Thu, 10 Sep 2026 14:50:06 +0100 Subject: [PATCH 2/2] test(codeql): capture core Swift extraction --- .github/workflows/codeql.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 48c66701e..c1ceba4d2 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -291,6 +291,9 @@ jobs: languages: swift build-mode: manual config-file: ./.github/codeql/codeql-config.yml + debug: true + debug-artifact-name: codeql-core-swift-debug + debug-database-name: core-swift-database - name: Type-check Swift modules for CodeQL run: .github/codeql/build_swift --typecheck