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 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) + } +}