Skip to content

Security: JS injection via unescaped checkout JSON in CheckoutV2ViewController #297

Description

@Rose-tech-dev

Summary

CheckoutV2ViewController embeds a JSON string directly into a JavaScript single-quoted string literal without escaping it first. If the JSON contains a single quote or backslash (both valid in, e.g., merchant references or customer names), the call breaks — or worse, arbitrary JavaScript executes in the WKWebView context.

Affected code

File: Sources/Afterpay/Checkout/CheckoutV2ViewController.swift

// Before (vulnerable):
bootstrapWebView.evaluateJavaScript("openCheckout('\(json)');")

If json contains ' or \, the resulting JS is syntactically broken or injectable.

Fix

Add a minimal escaping step before interpolation:

// String+JSEscaping.swift
extension String {
    func escapedForJSSingleQuotedString() -> String {
        return self
            .replacingOccurrences(of: "\\", with: "\\\\")
            .replacingOccurrences(of: "'", with: "\'")
    }
}

// CheckoutV2ViewController.swift
bootstrapWebView.evaluateJavaScript("openCheckout('\(json.escapedForJSSingleQuotedString())');")

Proof

A working fix and test (StringJSEscapingTests) are in this PR on a fork:
Rose-tech-dev#1

The test suite passes on macOS CI (Xcode 16.4, iOS 26 Simulator).

Impact

Any checkout JSON containing a single quote (e.g. customer name O'Brien) silently breaks the checkout flow. A maliciously crafted value could execute arbitrary JS inside the WKWebView.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions