{"id":164,"date":"2020-09-15T05:00:17","date_gmt":"2020-09-15T12:00:17","guid":{"rendered":"https:\/\/blog.mozilla.org\/attack-and-defense\/?p=164"},"modified":"2020-09-17T13:03:26","modified_gmt":"2020-09-17T20:03:26","slug":"inspecting-just-in-time-compiled-javascript","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/attack-and-defense\/2020\/09\/15\/inspecting-just-in-time-compiled-javascript\/","title":{"rendered":"Inspecting Just-in-Time Compiled JavaScript"},"content":{"rendered":"<p><span style=\"display:none\"><\/span><\/p>\n<p>The security implications of Just-in-Time (JIT) Compilers in browsers have been getting attention for the <a href=\"http:\/\/www.semantiscope.com\/research\/BHDC2010\/BHDC-2010-Paper.pdf\">past<\/a> <a href=\"https:\/\/www.nccgroup.com\/us\/about-us\/resources\/jit\/\">decade<\/a> and the <a href=\"https:\/\/labs.f-secure.com\/blog\/exploiting-cve-2019-17026-a-firefox-jit-bug\/\">references<\/a> <a href=\"https:\/\/i.blackhat.com\/asia-19\/Fri-March-29\/bh-asia-Li-Using-the-JIT-Vulnerability-to-Pwning-Microsoft-Edge.pdf\">to<\/a> <a href=\"https:\/\/www.blackhat.com\/us-19\/briefings\/schedule\/#the-most-secure-browser-pwning-chrome-from--to--16274\">more<\/a> <a href=\"https:\/\/googleprojectzero.blogspot.com\/2020\/09\/jitsploitation-one.html\">recent<\/a> <a href=\"https:\/\/www.jaybosamiya.com\/blog\/2019\/01\/02\/krautflare\/\">resources<\/a> <a href=\"https:\/\/blog.ret2.io\/2018\/06\/05\/pwn2own-2018-exploit-development\/\">is<\/a> <a href=\"https:\/\/github.com\/tunz\/js-vuln-db\">too<\/a> <a href=\"https:\/\/sensepost.com\/blog\/2020\/intro-to-chromes-v8-from-an-exploit-development-angle\/\">great<\/a> <a href=\"https:\/\/googleprojectzero.blogspot.com\/2018\/05\/bypassing-mitigations-by-attacking-jit.html\">to<\/a> <a href=\"https:\/\/www.youtube.com\/watch?v=A1FWvfkTgY4\">enumerate<\/a>. While it\u2019s not the <i>only<\/i> class of flaw in a browser, it is a common one; and diving deeply into it has a higher barrier to entry than, say, <a href=\"https:\/\/blog.mozilla.org\/attack-and-defense\/2019\/12\/02\/help-test-firefoxs-built-in-html-sanitizer-to-protect-against-uxss-bugs\/\">UXSS injection in the UI<\/a>. This post is about lowering that barrier to entry.<\/p>\n<style>\n\/* Thanks https:\/\/www.w3schools.com\/howto\/howto_js_tabs.asp *\/\n.tab {\n  overflow: hidden;<!--more-->\n  border: 1px solid #ccc;\n  background-color: #f1f1f1;\n}\n.tab button {\n  background-color: inherit;\n  float: left;\n  border: none;\n  outline: none;\n  cursor: pointer;\n  padding: 14px 16px;\n  transition: 0.3s;\n}\n.tab button:hover {\n  background-color: #ddd;\n}\n.tab button.active {\n  background-color: #ccc;\n}\n.tabcontent {\n  display: none;\n  padding: 6px 12px;\n  border: 1px solid #ccc;\n  border-top: none;\n} \n<\/style>\n<p>If you want to understand what is happening under the hood in the JIT engine, you can read the source. But that\u2019s kind of a tall order given that the folder <a href=\"https:\/\/searchfox.org\/mozilla-central\/source\/js\">js\/<\/a> contains 500,000+ lines of code. Sometimes it\u2019s easier to treat a target as a black box until you find something you want to dig into deeper. To aid in that endeavor, we\u2019ve landed a feature in the js shell that allows you to get the assembly output of a Javascript function the JIT has processed. Disassembly is supported with the <a href=\"https:\/\/zydis.re\/\">zydis disassembly library<\/a> (<a href=\"https:\/\/searchfox.org\/mozilla-central\/source\/js\/src\/zydis\">our in-tree version<\/a>).<\/p>\n<p>To use the new feature; you\u2019ll need to run the js interpreter. You can download the jsshell for any Nightly version of Firefox from <a href=\"https:\/\/ftp.mozilla.org\/pub\/firefox\/nightly\/latest-mozilla-central\/\">our FTP server<\/a> &#8211; for example <a href=\"https:\/\/ftp.mozilla.org\/pub\/firefox\/nightly\/latest-mozilla-central\/jsshell-linux-x86_64.zip\">here&#8217;s the latest Linux x64 jsshell<\/a>. Helpfully, these links always point to the latest version available, historical versions can <a href=\"https:\/\/ftp.mozilla.org\/pub\/firefox\/nightly\/2020\/09\/\">also be downloaded<\/a>.<\/p>\n<p>You can also <a href=\"https:\/\/firefox-source-docs.mozilla.org\/js\/build.html\">build the js shell from source<\/a> (which can be done separately from <a href=\"https:\/\/firefox-source-docs.mozilla.org\/setup\/index.html\">building Firefox<\/a>, but doing the full browser build can also create the shell.)\u00a0 If building from source, in your <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Mozilla\/Developer_guide\/Build_Instructions\/Configuring_Build_Options\">.mozconfig<\/a>, you\u2019ll want to following to get the tools and output you want but also emulate the shell as the Javascript engine is released to users:<\/p>\n<p><code><br \/>\nac_add_options --enable-application=js<br \/>\nac_add_options --enable-js-shell<br \/>\nac_add_options --enable-jitspew<br \/>\nac_add_options --disable-debug<br \/>\nac_add_options --enable-optimize<\/p>\n<p># If you want to experiment with the debug and optimize flags,<br \/>\n# you can build Firefox to different object directories<br \/>\n# (and avoid an entire recompilation)<br \/>\nmk_add_options MOZ_OBJDIR=@TOPSRCDIR@\/obj-nodebug-opt<br \/>\n# mk_add_options MOZ_OBJDIR=@TOPSRCDIR@\/obj-debug-noopt<\/code><\/p>\n<p>After building the shell or Firefox, fire up `obj-dir\/dist\/bin\/js[.exe]` and try the following script:<\/p>\n<p><code><\/code><\/p>\n<pre>function add(x, y) { x = 0+x; y = 0+y; return x+y; }\r\nfor(i=0; i&lt;500; i++) { add(2, i); }\r\nprint(disnative(add))\r\n<\/pre>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-167\" src=\"http:\/\/blog.mozilla.org\/attack-and-defense\/files\/2020\/09\/Screen-Shot-2020-09-09-at-4.04.29-PM.png\" alt=\"\" width=\"520\" height=\"180\" srcset=\"https:\/\/blog.mozilla.org\/attack-and-defense\/files\/2020\/09\/Screen-Shot-2020-09-09-at-4.04.29-PM.png 520w, https:\/\/blog.mozilla.org\/attack-and-defense\/files\/2020\/09\/Screen-Shot-2020-09-09-at-4.04.29-PM-300x104.png 300w\" sizes=\"(max-width: 520px) 100vw, 520px\" \/><\/p>\n<p>You\u2019ll be greeted by an initial line indicating which backend is being used. The possible values and their meanings are:<\/p>\n<ul>\n<li>Wasm &#8211; A WebAssembly function<sup>0<\/sup><\/li>\n<li>Asmjs &#8211; An asm.js module or exported function<\/li>\n<li>Baseline &#8211; indicates the Baseline JIT, a first-pass JIT Engine that collects type information (that can be used by Ion during a subsequent compilation).<\/li>\n<li>Ion &#8211; indicates IonMonkey, a powerful optimizing JIT that performs aggressive compiler optimizations at the cost of additional compile time.<\/li>\n<\/ul>\n<p><small><sup>0<\/sup> The WASM function itself might be Baseline WASM or compiled with an optimizing compiler Cranelift on Nightly; Ion otherwise &#8211; it\u2019s not easily enumerated which the assembly function is, but identifying baseline or not becomes easier once you\u2019ve looked at the assembly output a few times.<\/small><\/p>\n<p>After running a function <a href=\"https:\/\/searchfox.org\/mozilla-central\/rev\/2b250967a66886398e5e798371484fd018d88a22\/modules\/libpref\/init\/all.js#1079\">100 times<\/a>, we will trigger the Baseline compiler; after <a href=\"https:\/\/searchfox.org\/mozilla-central\/rev\/2b250967a66886398e5e798371484fd018d88a22\/modules\/libpref\/init\/all.js#1085\">1000 times<\/a> we will trigger Ion, and after <a href=\"https:\/\/searchfox.org\/mozilla-central\/rev\/2b250967a66886398e5e798371484fd018d88a22\/modules\/libpref\/init\/all.js#1086\">100,000 times<\/a> the full, more expensive, Ion compilation.<\/p>\n<p>For more information about the differences and internals of the JIT Engines, we can point to the following articles:<\/p>\n<ul>\n<li><a href=\"https:\/\/blog.mozilla.org\/javascript\/2013\/04\/05\/the-baseline-compiler-has-landed\/\">The Baseline Compiler Has Landed (2013)<\/a><\/li>\n<li><a href=\"https:\/\/blog.mozilla.org\/javascript\/2014\/07\/15\/ionmonkey-optimizing-away\/\">IonMonkey: Optimizing Away (2014)<\/a><\/li>\n<li><a href=\"https:\/\/blog.mozilla.org\/javascript\/2016\/07\/05\/ionmonkey-evil-on-your-behalf\/\">IonMonkey: Evil on your behalf (2016)<\/a><\/li>\n<li><a href=\"https:\/\/hacks.mozilla.org\/2019\/08\/the-baseline-interpreter-a-faster-js-interpreter-in-firefox-70\/\">The Baseline Interpreter (2019)<\/a><\/li>\n<li><a href=\"https:\/\/www.youtube.com\/playlist?list=PLo3w8EB99pqJVPhmYbYdInBvAGarDavh-\">The Compiler Compiler Youtube Series (2020)<\/a><\/li>\n<li><a href=\"https:\/\/mozilla-spidermonkey.github.io\/blog\/\">The SpiderMonkey Blog (2019-2020)<\/a><\/li>\n<li><a href=\"https:\/\/hacks.mozilla.org\/2017\/02\/a-cartoon-intro-to-webassembly\/\">A cartoon intro to WebAssembly (2017)<\/a><\/li>\n<li><a href=\"https:\/\/hacks.mozilla.org\/2018\/01\/making-webassembly-even-faster-firefoxs-new-streaming-and-tiering-compiler\/\">Making WebAssembly even faster (2018)<\/a><\/li>\n<li><a href=\"https:\/\/hacks.mozilla.org\/2018\/10\/calls-between-javascript-and-webassembly-are-finally-fast-%f0%9f%8e%89\/\">Calls between JavaScript and WebAssembly are finally fast (2018)<\/a><\/li>\n<\/ul>\n<p>Let\u2019s dive into the output we just generated.\u00a0 Here\u2019s the output of the above script:<\/p>\n<div class=\"tab\"><button id=\"BNCloud1Btn\" class=\" active\" onclick=\"showBN1()\">Binary Ninja Cloud<\/button><button id=\"Ascii1Btn\" onclick=\"showAscii1()\">ASCII<\/button><\/div>\n<div id=\"BNCloud1\" class=\"tabcontent\" style=\"display:block\">\n<iframe loading=\"lazy\" id=\"BinjaCloudEmbed1\" src=\"https:\/\/cloud.binary.ninja\/embed\/cdab8294-7865-453b-a154-29cf3bcf3ee8\" width=\"100%\" height=\"800px\"><\/iframe>\n<\/div>\n<div id=\"Ascii1\" class=\"tabcontent\">\n<pre>\r\n; backend=baseline\r\n00000000   jmp 0x0000000000000028                           \r\n00000005   mov $0x7F8A23923000, %rcx                           \r\n0000000F   movq 0x170(%rcx), %rcx                           \r\n00000016   movq %rsp, 0xD0(%rcx)                           \r\n0000001D   movq $0x00, 0xD8(%rcx)                                 \r\n00000028   push %rbp                                 \r\n\r\n00000029   mov %rsp, %rbp                |                 \r\n0000002C   sub $0x48, %rsp               | Allocating & initializing                  \r\n00000030   movl $0x00, -0x10(%rbp)       | BaselineFrame structure on                         \r\n00000037   movq 0x18(%rbp), %rcx         | stack.                        \r\n0000003B   and $-0x04, %rcx              | (BaselineCompilerCodeGen::\r\n0000003F   movq 0x28(%rcx), %rcx         |        emitInitFrameFields)                     \r\n00000043   movq %rcx, -0x30(%rbp)        |                         \r\n        \r\n00000047   mov $0x7F8A239237E0, %r11     |                     \r\n00000051   cmpq %rsp, (%r11)             |             \r\n00000054   jbe 0x000000000000006C        |                  \r\n0000005A   mov %rbp, %rbx                | Stackoverflow check         \r\n0000005D   sub $0x48, %rbx               | (BaselineCodeGen<Handler>::\r\n00000061   push %rbx                     |              emitStackCheck)          \r\n00000062   push $0x5821                  |        \r\n00000067   call 0xFFFFFFFFFFFE1680       |                   \r\n\r\n0000006C   mov $0x7F8A226CE0D8, %r11                           \r\n00000076   addq $0x01, (%r11)                           \r\n\r\n0000007A   mov $0x7F8A227F6E00, %rax     |                     \r\n00000084   movl 0xC0(%rax), %ecx         |                 \r\n0000008A   add $0x01, %ecx               |           \r\n0000008D   movl %ecx, 0xC0(%rax)         |                 \r\n00000093   cmp $0x3E8, %ecx              |            \r\n00000099   jl 0x00000000000000CC         | Check if we should tier up to\r\n0000009F   movq 0x88(%rax), %rax         | Ion code. 0x38 (1000) is the\r\n000000A6   cmp $0x02, %rax               | threshold. After that check,          \r\n000000AA   jz 0x00000000000000CC         | it checks 'are we already\r\n000000B0   cmp $0x01, %rax               | compiling' and 'is Ion\r\n000000B4   jz 0x00000000000000CC         | compilation impossible'                \r\n000000BA   mov %rbp, %rcx                |          \r\n000000BD   sub $0x48, %rcx               |           \r\n000000C1   push %rcx                     |     \r\n000000C2   push $0x5821                  |        \r\n000000C7   call 0xFFFFFFFFFFFE34B0       |                   \r\n\r\n000000CC   movq 0x28(%rbp), %rcx         |                 \r\n000000D0   mov $0x7F8A227F6ED0, %r11     |                     \r\n000000DA   movq (%r11), %rdi             |             \r\n000000DD   callq (%rdi)                  |  \r\n000000DF   movq 0x30(%rbp), %rcx         | Type Inference Type Monitors\r\n000000E3   mov $0x7F8A227F6EE0, %r11     | for |this| and each arg.    \r\n000000ED   movq (%r11), %rdi             | (This overhead is one of the           \r\n000000F0   callq (%rdi)                  |  reasons we're doing\r\n000000F2   movq 0x38(%rbp), %rcx         |  WARP - see below.)                                       \r\n000000F6   mov $0x7F8A227F6EF0, %r11     |                     \r\n00000100   movq (%r11), %rdi             |             \r\n00000103   callq (%rdi)                  |        \r\n\r\n00000105   movq 0x30(%rbp), %rbx         |                 \r\n00000109   mov $0xFFF8800000000000, %rcx |                         \r\n00000113   mov $0x7F8A227F6F00, %r11     | Load Int32Value(0) + arg1 and                    \r\n0000011D   movq (%r11), %rdi             | calling an Inline Cache stub            \r\n00000120   callq (%rdi)                  |        \r\n00000122   movq %rcx, 0x30(%rbp)         |                 \r\n\r\n00000126   movq 0x38(%rbp), %rbx         |                 \r\n0000012A   mov $0xFFF8800000000000, %rcx | Load Int32Value(0) + arg2 and                        \r\n00000134   mov $0x7F8A227F6F10, %r11     | calling an Inline Cache stub                               \r\n0000013E   movq (%r11), %rdi             |             \r\n00000141   callq (%rdi)                  |        \r\n00000143   movq %rcx, 0x38(%rbp)         |                  \r\n\r\n00000147   movq 0x38(%rbp), %rbx         |                 \r\n0000014B   movq 0x30(%rbp), %rcx         |                 \r\n0000014F   mov $0x7F8A227F6F20, %r11     |                     \r\n00000159   movq (%r11), %rdi             | Final Add Inline Cache call\r\n0000015C   callq (%rdi)                  | followed by epilogue code and\r\n0000015E   jmp 0x0000000000000163        | return       \r\n00000163   mov %rbp, %rsp                |          \r\n00000166   pop %rbp                      |    \r\n00000167   jmp 0x0000000000000171        |                  \r\n0000016C   jmp 0xFFFFFFFFFFFE69E0                           \r\n00000171   ret                           \r\n00000172   ud2                           \r\n<\/pre>\n<\/div>\n<p><script type=\"text\/javascript\">\nfunction showBN1() {\ndocument.getElementById('BNCloud1').style.display = 'block';\ndocument.getElementById('Ascii1').style.display = 'none';\ndocument.getElementById('BNCloud1Btn').className += \" active\";\ndocument.getElementById('Ascii1Btn').className = \ndocument.getElementById('Ascii1Btn').className.replace(\" active\", \"\");\n}\nfunction showAscii1() {\ndocument.getElementById('BNCloud1').style.display = 'none';\ndocument.getElementById('Ascii1').style.display = 'block';\ndocument.getElementById('BNCloud1Btn').className = \ndocument.getElementById('BNCloud1Btn').className.replace(\" active\", \"\");\ndocument.getElementById('Ascii1Btn').className += \" active\";\n}\n<\/script><\/p>\n<p>So that\u2019s the Baseline code. It\u2019s the more simplistic JIT in Firefox. What about IonMonkey &#8211; its faster, more aggressive big brother?<\/p>\n<p>If we preface our script with <tt>setJitCompilerOption(\"ion.warmup.trigger\", 4);<\/tt> then we will induce the Ion compiler to trigger earlier instead of the aforementioned <a href=\"https:\/\/searchfox.org\/mozilla-central\/rev\/2b250967a66886398e5e798371484fd018d88a22\/modules\/libpref\/init\/all.js#1085\">1000 invocations<\/a>. You can also set <tt>setJitCompilerOption(\"ion.full.warmup.trigger\", 4);<\/tt> to trigger the more aggressive tier for Ion compilation that otherwise kicks in after <a href=\"https:\/\/searchfox.org\/mozilla-central\/rev\/2b250967a66886398e5e798371484fd018d88a22\/modules\/libpref\/init\/all.js#1086\">100,000 invocations<\/a>. After triggering the \u2018full\u2019 layer, the output will look like:<\/p>\n<div class=\"tab\"><button id=\"BNCloud2Btn\" class=\" active\" onclick=\"showBN2()\">Binary Ninja Cloud<\/button><button id=\"Ascii2Btn\" onclick=\"showAscii2()\">ASCII<\/button><\/div>\n<div id=\"BNCloud2\" class=\"tabcontent\" style=\"display:block\">\n<iframe loading=\"lazy\" id=\"BinjaCloudEmbed2\" src=\"https:\/\/cloud.binary.ninja\/embed\/41afad0b-ea62-4e76-90d8-1c1faf7f1503\" width=\"100%\" height=\"800px\"><\/iframe>\n<\/div>\n<div id=\"Ascii2\" class=\"tabcontent\">\n<pre>\r\n; backend=ion\r\n00000000    movq 0x20(%rsp), %rax         |\r\n00000005    shr $0x2F, %rax               |\r\n00000009    cmp $0x1FFF3, %eax            |\r\n0000000E    jnz 0x0000000000000078        |\r\n00000014    movq 0x28(%rsp), %rax         |\r\n00000019    shr $0x2F, %rax               | Type Guards\r\n0000001D    cmp $0x1FFF1, %eax            | for this variable,\r\n00000022    jnz 0x0000000000000078        | arg1, & arg2\r\n00000028    movq 0x30(%rsp), %rax         | \r\n0000002D    shr $0x2F, %rax               |\r\n00000031    cmp $0x1FFF1, %eax            |\r\n00000036    jnz 0x0000000000000078        |\r\n0000003C    jmp 0x0000000000000041        |\r\n\r\n00000041    movl 0x28(%rsp), %eax         |\r\n00000045    movl 0x30(%rsp), %ecx         | Addition\r\n00000049    add %ecx, %eax                |\r\n\r\n0000004B    jo 0x000000000000007F         | Overflow Check\r\n\r\n00000051    mov $0xFFF8800000000000, %rcx | Box int32 into\r\n0000005B    or %rax, %rcx                 | Int32Value\r\n0000005E    ret\r\n0000005F    nop\r\n00000060    nop\r\n00000061    nop\r\n00000062    nop\r\n00000063    nop\r\n00000064    nop\r\n00000065    nop\r\n00000066    nop\r\n00000067    mov $0x7F8A23903FC0, %r11     |\r\n00000071    push %r11                     |\r\n00000073    jmp 0xFFFFFFFFFFFDED40        |\r\n00000078    push $0x00                    |\r\n0000007A    jmp 0x000000000000008D        |\r\n0000007F    sub %ecx, %eax                | Out-of-line\r\n00000081    jmp 0x0000000000000086        | error handling\r\n00000086    push $0x0D                    | code\r\n00000088    jmp 0x000000000000008D        |\r\n0000008D    push $0x00                    |\r\n0000008F    jmp 0xFFFFFFFFFFFDEC60        |\r\n00000094    ud2                           |\r\n<\/pre>\n<\/div>\n<p><script type=\"text\/javascript\">\nfunction showBN2() {\ndocument.getElementById('BNCloud2').style.display = 'block';\ndocument.getElementById('Ascii2').style.display = 'none';\ndocument.getElementById('BNCloud2Btn').className += \" active\";\ndocument.getElementById('Ascii2Btn').className = \ndocument.getElementById('Ascii2Btn').className.replace(\" active\", \"\");\n}\nfunction showAscii2() {\ndocument.getElementById('BNCloud2').style.display = 'none';\ndocument.getElementById('Ascii2').style.display = 'block';\ndocument.getElementById('BNCloud2Btn').className = \ndocument.getElementById('BNCloud2Btn').className.replace(\" active\", \"\");\ndocument.getElementById('Ascii2Btn').className += \" active\";\n}\n<\/script><\/p>\n<p>There are some other things worth noting.<\/p>\n<p>You can control the behavior of the JITs using environment variables, such as <tt>JIT_OPTION_fullDebugChecks=false<\/tt> (this will avoid running all the debug checks even in the debug build.)\u00a0 The full list of JIT Options with documentation is available in <a href=\"https:\/\/searchfox.org\/mozilla-central\/source\/js\/src\/jit\/JitOptions.cpp\">JitOptions.cpp<\/a>.<\/p>\n<p>There are also a variety of command-line flags that can be used in place of environment variables or <tt>setJitCompilerOption<\/tt>. For instance <tt>--baseline-eager<\/tt> and <tt>--ion-eager<\/tt> will trigger JIT compilation immediately instead of requiring multiple compilations. (ion-eager triggers \u2018full\u2019 compilation, so avoid it if you want the non-full behavior.) <tt>--no-threads<\/tt> or <tt>--ion-offthread-compile=off<\/tt> will disable off-thread compilation that can make it harder to write reliable tests because it adds non-determinism. no-threads turns off all the background threads and implies ion-offthread-compile=off.<\/p>\n<p>Finally, we have a new in-development frontend for Ion: WarpBuilder. You can learn more about WarpBuilder over in the <a href=\"https:\/\/mozilla-spidermonkey.github.io\/blog\/2020\/03\/12\/newsletter-3.html\">spidermonkey<\/a> <a href=\"https:\/\/mozilla-spidermonkey.github.io\/blog\/2020\/05\/11\/newsletter-4.html\">newsletter<\/a> <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=1613592\">or the Bugzilla bug<\/a>. Enabling warp (by passing <tt>--warp<\/tt> to the js shell executable) significantly reduces the assembly generated, partly because we&#8217;re simplifying how type information is collected and updated.<\/p>\n<p>If you\u2019ve got other tricks or techniques you use to help you navigate our JIT(s), be sure to <a href=\"https:\/\/twitter.com\/attackndefense\/status\/1305859067496275970\">reply to our tweet<\/a> so others can find them!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The security implications of Just-in-Time (JIT) Compilers in browsers have been getting attention for the past decade and the references to more recent resources is too great to enumerate. While &hellip; <a class=\"go\" href=\"https:\/\/blog.mozilla.org\/attack-and-defense\/2020\/09\/15\/inspecting-just-in-time-compiled-javascript\/\">Read more<\/a><\/p>\n","protected":false},"author":1610,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[449530],"tags":[],"coauthors":[323226,449531,449532],"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/posts\/164"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/users\/1610"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/comments?post=164"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/posts\/164\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/media?parent=164"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/categories?post=164"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/tags?post=164"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blog.mozilla.org\/attack-and-defense\/wp-json\/wp\/v2\/coauthors?post=164"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}