javascript-obfuscator 5.7.0 → 5.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  Change Log
2
2
 
3
+ v5.8.0
4
+ ---
5
+ * Pro API: added support for custom presets. `optionsPreset` accepts the alias of a custom preset saved in the obfuscator.io dashboard; `obfuscatePro()` and the CLI (`--pro-api-token`) fetch it and merge its options
6
+ * CLI: `--options-preset` with a VM preset name (e.g. `vm-default`) no longer fails locally when `--pro-api-token` is set; the name is passed to the Pro API
7
+
3
8
  v5.7.0
4
9
  ---
5
10
  * **New option:** `advertisement` allows to control the display of the JavaScript Obfuscator Pro advertisement message in the console. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1448
package/README.md CHANGED
@@ -91,7 +91,6 @@ The example of obfuscated code: [github.com](https://github.com/javascript-obfus
91
91
  [![Coverage Status](https://coveralls.io/repos/github/javascript-obfuscator/javascript-obfuscator/badge.svg)](https://coveralls.io/github/javascript-obfuscator/javascript-obfuscator)
92
92
  [![Backers on Open Collective](https://opencollective.com/javascript-obfuscator/backers/badge.svg)](#backers)
93
93
  [![Sponsors on Open Collective](https://opencollective.com/javascript-obfuscator/sponsors/badge.svg)](#sponsors)
94
- [![xscode](https://img.shields.io/badge/Available%20on-xs%3Acode-blue?style=?style=plastic&logo=appveyor&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF////////VXz1bAAAAAJ0Uk5T/wDltzBKAAAAlUlEQVR42uzXSwqAMAwE0Mn9L+3Ggtgkk35QwcnSJo9S+yGwM9DCooCbgn4YrJ4CIPUcQF7/XSBbx2TEz4sAZ2q1RAECBAiYBlCtvwN+KiYAlG7UDGj59MViT9hOwEqAhYCtAsUZvL6I6W8c2wcbd+LIWSCHSTeSAAECngN4xxIDSK9f4B9t377Wd7H5Nt7/Xz8eAgwAvesLRjYYPuUAAAAASUVORK5CYII=)](https://xscode.com/sanex3339/javascript-obfuscator)
95
94
 
96
95
  #### *NOTE! the README on the master branch might not match that of the latest stable release!*
97
96
 
@@ -421,6 +420,29 @@ if (ProApiClient.hasProFeatures(options)) {
421
420
  Pro features include:
422
421
  - `vmObfuscation: true` – VM-based bytecode obfuscation
423
422
  - `parseHtml: true` – HTML parsing with inline JavaScript obfuscation
423
+ - `optionsPreset` set to a VM preset (`vm-default`, ...) or to a [custom preset](#custom-presets) alias – only the Pro API can resolve these
424
+
425
+ ### Custom Presets :new:
426
+
427
+ Save a configuration in the [obfuscator.io](https://obfuscator.io) dashboard as a custom preset and give it an **API alias** in the save dialog. Set `optionsPreset` to that alias and `obfuscatePro()` fetches the preset's options before obfuscating, so the configuration lives in the dashboard and changes there apply to the next build:
428
+
429
+ ```javascript
430
+ const result = await JavaScriptObfuscator.obfuscatePro(
431
+ sourceCode,
432
+ { optionsPreset: 'production' },
433
+ { apiToken: 'YOUR_API_TOKEN' }
434
+ );
435
+ ```
436
+
437
+ The preset's options are the base and any other option you pass overrides them, the same way built-in presets are merged. A custom preset with no Pro feature enabled is obfuscated locally with its options. A team service key resolves the team owner's presets; a member's personal key resolves their own presets plus the ones shared with the team.
438
+
439
+ An alias that does not exist for your account throws an `ApiError` with `statusCode` 404. Without an API token (`obfuscate()`), only the built-in presets are available.
440
+
441
+ The same works from the CLI:
442
+
443
+ ```sh
444
+ javascript-obfuscator input.js --pro-api-token YOUR_API_TOKEN --options-preset production -o output.js
445
+ ```
424
446
 
425
447
  ### Error Handling
426
448
 
@@ -456,7 +478,7 @@ javascript-obfuscator input.js --pro-api-token YOUR_API_TOKEN --pro-api-version
456
478
  - `--pro-api-token <string>` – Your API token from [obfuscator.io](https://obfuscator.io)
457
479
  - `--pro-api-version <string>` – Obfuscator.io version to use (optional, defaults to latest)
458
480
 
459
- The CLI automatically detects when Pro features (`vmObfuscation` or `parseHtml`) are enabled and routes the request through the Pro API.
481
+ The CLI automatically detects when Pro features (`vmObfuscation`, `parseHtml`, or an `optionsPreset` naming a VM preset or a [custom preset](#custom-presets)) are enabled and routes the request through the Pro API.
460
482
 
461
483
  ### Large File Uploads
462
484
 
@@ -1142,6 +1164,10 @@ Available values:
1142
1164
  * `medium-obfuscation`;
1143
1165
  * `high-obfuscation`.
1144
1166
 
1167
+ With `obfuscatePro()` or `--pro-api-token` the following are also accepted and resolved by the Pro API:
1168
+ * the VM presets: `vm-low-obfuscation`, `vm-default`, `vm-medium-obfuscation`, `vm-high-obfuscation`, `vm-ultra-high-obfuscation`, `vm-anti-llm`;
1169
+ * the alias of a [custom preset](#custom-presets) saved in the [obfuscator.io](https://obfuscator.io) dashboard.
1170
+
1145
1171
  All addition options will be merged with selected options preset.
1146
1172
 
1147
1173
  ### `renameGlobals`
@@ -1925,8 +1951,8 @@ Specify exactly which root-level functions should get VM protection by name.
1925
1951
  **Example:**
1926
1952
  ```javascript
1927
1953
  {
1928
- vmObfuscation: true,
1929
- vmTargetFunctions: ['someFunctionName']
1954
+ vmObfuscation: true,
1955
+ vmTargetFunctions: ['someFunctionName']
1930
1956
  }
1931
1957
  ```
1932
1958
 
@@ -1940,8 +1966,8 @@ Specify root-level functions that should never get VM protection. Takes preceden
1940
1966
  **Example:**
1941
1967
  ```javascript
1942
1968
  {
1943
- vmObfuscation: true,
1944
- vmExcludeFunctions: ['someFunctionName']
1969
+ vmObfuscation: true,
1970
+ vmExcludeFunctions: ['someFunctionName']
1945
1971
  }
1946
1972
  ```
1947
1973
 
@@ -1961,28 +1987,28 @@ Controls how functions/methods are selected for VM obfuscation.
1961
1987
  ```javascript
1962
1988
  // Source code
1963
1989
  function regularFunction() {
1964
- return 'not virtualized';
1990
+ return 'not virtualized';
1965
1991
  }
1966
1992
 
1967
1993
  /* javascript-obfuscator:vm */
1968
1994
  function sensitiveFunction() {
1969
- return 'this will be VM-protected';
1995
+ return 'this will be VM-protected';
1970
1996
  }
1971
1997
 
1972
1998
  function outer() {
1973
- /* javascript-obfuscator:vm */
1974
- function nestedSensitive() {
1975
- return 'nested but still VM-protected';
1976
- }
1977
- return nestedSensitive();
1999
+ /* javascript-obfuscator:vm */
2000
+ function nestedSensitive() {
2001
+ return 'nested but still VM-protected';
2002
+ }
2003
+ return nestedSensitive();
1978
2004
  }
1979
2005
  ```
1980
2006
 
1981
2007
  ```javascript
1982
2008
  // Obfuscator options
1983
2009
  {
1984
- vmObfuscation: true,
1985
- vmTargetFunctionsMode: 'comment'
2010
+ vmObfuscation: true,
2011
+ vmTargetFunctionsMode: 'comment'
1986
2012
  }
1987
2013
  ```
1988
2014
 
@@ -2043,6 +2069,8 @@ const MY_STRING = (() => { return /* VM bytecode call */ })(); // String hidden
2043
2069
 
2044
2070
  **Note:** This option only works when `vmTargetFunctionsMode` is `'root'` (the default).
2045
2071
 
2072
+ **Warnings:** Whenever a top-level initializer ends up in plain JavaScript under VM obfuscation, a `VMTopLevelInitializerNotVirtualized` warning listing the affected variable names is reported. That covers: this option being disabled, initializers this option had to skip (each with the reason — e.g. the initializer references a sibling declarator or contains top-level await), and `vmAsyncExecutor` mode where the synchronous wrappers can't be virtualized at all.
2073
+
2046
2074
  ### `vmDynamicOpcodes`
2047
2075
  Type: `boolean` Default: `false`
2048
2076
 
@@ -2057,7 +2085,7 @@ As the result - smaller output and each build looks different.
2057
2085
  ### `vmBytecodeEncoding`
2058
2086
  Type: `boolean` Default: `false`
2059
2087
 
2060
- Encodes each bytecode instruction. Instructions are decoded one at a time during execution.
2088
+ Encodes each bytecode instruction (decoded one at a time during execution) and masks the string constants stored in the bytecode pool, so plaintext strings do not sit in the compiled bytecode.
2061
2089
 
2062
2090
  ### `vmBytecodeArrayEncoding`
2063
2091
  Type: `boolean` Default: `false`
@@ -2076,11 +2104,15 @@ This option externalizes the encryption key - it's not embedded in the obfuscate
2076
2104
  ### `vmBytecodeArrayEncodingKeyGetter`
2077
2105
  Type: `string` Default: `''`
2078
2106
 
2079
- **Synchronous** JavaScript expression that **returns** the encryption key at runtime. This expression is evaluated when the obfuscated code loads, and must return the same key that was provided in `vmBytecodeArrayEncodingKey`.
2107
+ **Synchronous** JavaScript expression that **returns** the encryption key at runtime. This expression is evaluated when the obfuscated code loads, and must return the same key that was provided in `vmBytecodeArrayEncodingKey`. To resolve the key **asynchronously** (a `Promise`), enable [`vmAsyncExecutor`](#vmasyncexecutor).
2080
2108
 
2081
- **The obfuscated code will only work when the key getter returns exactly the same key that was used during obfuscation.** If the keys don't match, decryption will fail and the code will produce garbage or errors. If the key getter returns `undefined`, `null`, or an empty string, the code will throw an error: "VM decryption key not available".
2109
+ > **Note:** a Promise-returning getter requires `vmAsyncExecutor`. This can't be checked at build time, so a Promise getter with `vmAsyncExecutor` **off** fails at runtime the decoder receives the Promise instead of the key.
2082
2110
 
2083
- **Important:** The key should NOT be defined in the same JavaScript file/script as the obfuscated code. Doing so defeats the purpose of key externalization, as static analysis could still find the key. Store the key in a separate source: server-set cookies, localStorage populated by another script, server-injected HTML meta tags, or a global variable set by a different script that loads before the obfuscated code.
2111
+ **The obfuscated code will only work when the key getter returns exactly the same key that was used during obfuscation.** If the keys don't match or the getter returns `undefined`, `null`, or an empty string decryption produces a wrong keystream and the code fails at runtime with garbage output or an ordinary runtime error. There is deliberately no distinct, key-specific error message, so a failed key is indistinguishable from any other runtime fault.
2112
+
2113
+ **Important:** Keep the key out of the same file/script as the obfuscated code — inlining it there lets even a purely **static** scan of the bundle recover it. Store it in a separate source instead: server-set cookies, `localStorage` populated by another script, a server-injected HTML meta tag, a global set by a different script, or (with [`vmAsyncExecutor`](#vmasyncexecutor)) fetched from your backend at runtime.
2114
+
2115
+ When the key is fetched from your backend (via [`vmAsyncExecutor`](#vmasyncexecutor)), add session- or origin-based checks on that endpoint: return the correct key to real users (valid session, expected `Origin`/`Referer`) and a garbage key to suspicious requests (e.g. a `localhost`/unexpected origin, no session). Real users run normally; a copy running outside your environment gets a key that decrypts to nothing. The exact logic depends on your site.
2084
2116
 
2085
2117
  Examples:
2086
2118
  ```ts
@@ -2098,16 +2130,19 @@ vmBytecodeArrayEncodingKeyGetter: "document.querySelector('meta[name=\"vm-key\"]
2098
2130
 
2099
2131
  // From nested object
2100
2132
  vmBytecodeArrayEncodingKeyGetter: "window.config.encryption.key"
2133
+
2134
+ // From backend, async (requires vmAsyncExecutor)
2135
+ vmBytecodeArrayEncodingKeyGetter: 'fetch("/vm-key").then((res) => res.text())'
2101
2136
  ```
2102
2137
 
2103
2138
  **Usage example:**
2104
2139
  ```ts
2105
2140
  // Build time
2106
2141
  JavaScriptObfuscator.obfuscate(code, {
2107
- vmObfuscation: true,
2108
- vmBytecodeArrayEncoding: true,
2109
- vmBytecodeArrayEncodingKey: 'mySecretKey123',
2110
- vmBytecodeArrayEncodingKeyGetter: 'window.__VM_KEY__'
2142
+ vmObfuscation: true,
2143
+ vmBytecodeArrayEncoding: true,
2144
+ vmBytecodeArrayEncodingKey: 'mySecretKey123',
2145
+ vmBytecodeArrayEncodingKeyGetter: 'window.__VM_KEY__'
2111
2146
  });
2112
2147
 
2113
2148
  // Runtime - key must be set before obfuscated code runs
@@ -2157,25 +2192,36 @@ Type: `boolean` Default: `false`
2157
2192
 
2158
2193
  Encodes jump targets in the bytecode. Jump offsets are calculated at runtime, hiding the control flow structure (`if`/`else`, loops, etc.) from static analysis.
2159
2194
 
2160
- ### `vmDecoyOpcodes`
2195
+ ### `vmMacroOps`
2161
2196
  Type: `boolean` Default: `false`
2162
2197
 
2163
- Adds fake opcode handlers to the VM dispatcher that are never called. For example, if the VM uses 20 real opcodes, this might add 30 fake handlers, making the interpreter appear more complex than it really is.
2198
+ Combines common instruction sequences into single "macro" opcodes. For example, `LOAD_ARG + PUSH_CONST + SUB` can become `MACRO_SUB_ARG_CONST`, reducing interpreter dispatches. This works with both the default stack VM and `vmRegisterBased: true`; enable `vmMacroOps: true` explicitly in either mode.
2164
2199
 
2165
- ### `vmDeadCodeInjection`
2166
- Type: `boolean` Default: `false`
2200
+ ### `vmDebugProtection`
2201
+ Type: `boolean | object` Default: `false`
2167
2202
 
2168
- Injects fake bytecode sequences that are never executed. These look like real instructions but are skipped during runtime, confusing analysis tools that process them.
2203
+ Adds multi-layered anti-debugging, anti-analysis, and anti-LLM defenses to the VM runtime. Works best with `browser`/`browser-no-eval` targets.
2169
2204
 
2170
- ### `vmMacroOps`
2171
- Type: `boolean` Default: `false`
2205
+ Pass `true` to enable it, or `false` to disable it. Pass an object to enable it while turning off a specific defense:
2172
2206
 
2173
- Combines common instruction sequences into single "macro" opcodes. For example, `LOAD + ADD + STORE` might become a single `MACRO_ADD_TO_VAR` instruction. This breaks pattern recognition and can improve performance.
2207
+ ```js
2208
+ {
2209
+ vmDebugProtection: {
2210
+ // most defenses are always on; but CDP/devtools detection is disabled
2211
+ inspectorDetection: false
2212
+ }
2213
+ }
2214
+ ```
2174
2215
 
2175
- ### `vmDebugProtection`
2176
- Type: `boolean` Default: `false`
2216
+ > :warning: **The object is not a menu of defenses to switch on.** When debug protection is enabled, the great majority of its defenses are **always active and cannot be turned off**. The sub-options below expose only the small number of defenses that some consumers may deliberately need to relax (for example, because a false positive would break a legitimate workflow) — every other defense stays on regardless.
2217
+
2218
+ | Sub-option | Type | Default | Description |
2219
+ | --- | --- | --- | --- |
2220
+ | `inspectorDetection` | `boolean` | `true` | Detect and react to an attached CDP (Chrome DevTools Protocol) inspector — both the CDP `Runtime` domain being enabled (`Runtime.enable`) and an active debugger (the CDP `Debugger` domain, e.g. breakpoints or the developer-tools Sources panel). **Opening the browser's developer tools enables those domains, so an open inspector is detected and reacted to.** Keeping it enabled is recommended; set it to `false` only if your users legitimately open developer tools. |
2177
2221
 
2178
- Adds multi-layered anti-debugging, anti-analysis, and anti-LLM defenses to the VM runtime. For best results, allow `unsafe-eval` in your Content Security Policy. Works best with `browser`/`browser-no-eval` targets.
2222
+ > :bulb: The object form is available through the API
2223
+
2224
+ > :warning: **Automation frameworks.** With `inspectorDetection` on (the default), driving the protected page with a CDP-based tool (Puppeteer, Playwright, Selenium/ChromeDriver) is detected as an attached inspector. If you run automated tests against protected code, build those with `vmDebugProtection: { inspectorDetection: false }`.
2179
2225
 
2180
2226
  ### `vmSelfDefending`
2181
2227
  Type: `boolean` Default: `false`
@@ -2184,12 +2230,21 @@ Adds multi-layered tamper detection, anti-hooking, and anti-reverse-engineering
2184
2230
 
2185
2231
  > :warning: This option force-enables [`vmBytecodeArrayEncoding`](#vmbytecodeArrayEncoding).
2186
2232
 
2233
+ > :warning: **Sensitive environment detection.** This option binds the obfuscated code to its target runtime environment and uses advanced browser fingerprinting to detect automation tools. Code protected with this option **will intentionally break** when run in:
2234
+ > - Headless browsers (headless Chrome/Chromium, PhantomJS)
2235
+ > - Browser automation tools (Puppeteer, Playwright, Cypress, Selenium/ChromeDriver, Nightmare)
2236
+ > - Node.js (when `target` is set to `browser`)
2237
+ > - jsdom or similar server-side DOM emulations
2238
+ > - Environments where native browser builtins have been hooked or replaced
2239
+ >
2240
+ > The code **will work correctly** in regular browsers (Chrome, Firefox, Safari, Edge), including when loaded inside iframes, browser extensions (content scripts), and Web Workers. If you need to run automated tests against protected code, disable `vmSelfDefending` for test builds — this option is designed to prevent automated analysis and **cannot be safely used with any automation framework**.
2241
+
2187
2242
  Strongly recommended to use together with [`vmDebugProtection`](#vmDebugProtection), [`vmBytecodeArrayEncodingKey`](#vmbytecodeArrayEncodingKey), and [`vmBytecodeArrayEncodingKeyGetter`](#vmbytecodeArrayEncodingKeyGetter).
2188
2243
 
2189
2244
  ### `vmDefenseHook`
2190
- Type: `{ name: string, aliases?: object }` Default: `''`
2245
+ Type: `{ name: string, aliases?: object } | null` Default: `null`
2191
2246
 
2192
- `vmDefenseHook` takes an object with two keys: **`name`** (required) and **`aliases`** (optional).
2247
+ `vmDefenseHook` is `null` (disabled) or an object with two keys: **`name`** (required) and **`aliases`** (optional).
2193
2248
 
2194
2249
  `name` is a **global function your host page defines** that a VM defense (`vmDebugProtection` / `vmSelfDefending`) calls with a signal object when it detects a hostile signal — a debugger or inspector, a headless / automation browser, an AI-coding-agent process, a disallowed domain, and so on. Use it to report the event to your backend (e.g. `navigator.sendBeacon`). The hook is a **pure telemetry sink**: its return value is ignored, and a missing or throwing hook is a silent no-op that can never disable a defense. To change what a defense *does* on detection, use [`vmDefenseReaction`](#vmdefensereaction).
2195
2250
 
@@ -2249,8 +2304,6 @@ vmDefenseHook: {
2249
2304
 
2250
2305
  This is fingerprint avoidance, not secrecy — the mapping can still be inferred by repeated testing — so its only benefit is not exposing stable, self-explanatory names. Unset entries keep their default names.
2251
2306
 
2252
- > A bare string (`vmDefenseHook: '__vmDetection'`) is accepted as shorthand for `{ name: '__vmDetection' }` but is **deprecated** — prefer the object form.
2253
-
2254
2307
  ### `vmDefenseReaction`
2255
2308
  Type: `object` Default: `{ automation: 'break', debugger: 'decoy', sandbox: 'decoy', domain: 'break', tamper: 'break', integrity: 'break' }`
2256
2309
 
@@ -2285,17 +2338,33 @@ vmDefenseReaction: { automation: 'none', domain: 'break' } // tolerate automat
2285
2338
  ### `browserEnvironment`
2286
2339
  Type: `object` Default: `{}`
2287
2340
 
2288
- Declares facts about the environment your production build is served in, so the protected code can bind itself to them. Only takes effect together with [`vmSelfDefending`](#vmselfdefending), and only for `browser` / `browser-no-eval` / `service-worker` targets — it is rejected for `node`, `userscript`, and `bytenode`.
2341
+ Declares facts about the environment your production build runs in, so the protected code can bind to, react to, or tolerate them. Available only for `browser` / `browser-no-eval` / `service-worker` targets — it is rejected for `node`, `userscript`, and `bytenode`. Each field takes effect together with a specific protection, noted below.
2289
2342
 
2290
- Currently one field:
2343
+ Fields:
2291
2344
 
2292
- - **`transport`** — the scheme your production serves the bundle over: `'http'` or `'https'`. With `'https'`, the build ties its integrity to being served over HTTPS, so a copy an analyst lifts and serves over plain HTTP (a common local reverse-engineering setup) will not run correctly. `'http'` or an unset field adds no binding.
2345
+ - **`transport`** — the scheme your production serves the bundle over: `'http'` or `'https'`. With `'https'`, the build ties its integrity to being served over HTTPS, so a copy an analyst lifts and serves over plain HTTP (a common local reverse-engineering setup) will not run correctly. `'http'` or an unset field adds no binding. Takes effect with [`vmSelfDefending`](#vmselfdefending).
2293
2346
 
2294
2347
  ```js
2295
2348
  browserEnvironment: { transport: 'https' }
2296
2349
  ```
2297
2350
 
2298
- > :warning: A build declared `transport: 'https'` runs correctly **only** where it is actually served over `https:`. Every other scheme corrupts it, so declare it only when every context that loads your production build is HTTPS. That excludes: plain `http://` (including `http://localhost` in development), `file://` (Electron / Cordova / packaged apps), and `blob:` / `about:` embeddings (a bundle running inside an `about:blank` or `srcdoc` iframe). A client-side HTTP→HTTPS redirect still renders the HTTP page first, so the bundle must not run before the redirect completes.
2351
+ - **`hosting`** where your production bundle is served from: `'remote'` or `'local'`. With `'remote'`, the build ties its integrity to being served from a remote host, so a copy an analyst lifts and runs in their own local setup is treated as a runtime-environment mismatch and the automation defenses react (see [`vmDebugProtection`](#vmdebugprotection) and [`vmDefenseReaction`](#vmdefensereaction)). `'local'` or an unset field adds no binding. Takes effect with `vmDebugProtection`, on `browser` / `browser-no-eval` only.
2352
+
2353
+ ```js
2354
+ browserEnvironment: { transport: 'https', hosting: 'remote' }
2355
+ ```
2356
+
2357
+ - **`hookedBuiltins`** — set to `true` to declare that the runtime your production build runs in legitimately replaces native builtins with JavaScript wrappers: the app's own anti-tamper, the host page, or other browser extensions sharing the same realm. [`vmSelfDefending`](#vmselfdefending) normally treats a replaced native builtin as tampering and stops the build from running; with this set, it tolerates such an environment and the code runs. `false` or an unset field keeps the strict behavior. Takes effect with [`vmSelfDefending`](#vmselfdefending).
2358
+
2359
+ ```js
2360
+ browserEnvironment: { hookedBuiltins: true }
2361
+ ```
2362
+
2363
+ This option relaxes nativity checks only; clean-realm validation and required builtin behavior remain enforced.
2364
+
2365
+ > :warning: `hookedBuiltins` deliberately relaxes tamper detection: once it is set, an analyst who wraps those same builtins to inspect your code is no longer stopped either. The VM virtualization, anti-debugging, and integrity protections are unaffected. Enable it only when your production runtime is known to hook builtins and that weaker guarantee is acceptable.
2366
+
2367
+ > :warning: The `transport` and `hosting` fields bind the protected build to the environment you declare. The same build loaded in any environment that does not match — including transiently, before it reaches its final one — will not run correctly, by design. Declare a field only when every context that loads your production build matches it, and keep these declarations off the builds you use for local development, testing, and CI.
2299
2368
 
2300
2369
  ### `vmStatefulOpcodes`
2301
2370
  Type: `boolean` Default: `false`
@@ -2354,7 +2423,6 @@ When enabled, the string array will **only** extract strings from bytecode data
2354
2423
  - When `vmBytecodeArrayEncoding: true` — top-level base64 encoded bytecode strings are extracted
2355
2424
  - `stringArrayThreshold` still controls what percentage of those bytecode strings are extracted
2356
2425
 
2357
-
2358
2426
  ### `vmDomainLock`
2359
2427
  Type: `string[]` Default: `[]`
2360
2428
 
@@ -2374,81 +2442,6 @@ Type: `string` Default: `about:blank`
2374
2442
 
2375
2443
  Allows the browser to be redirected to a passed URL if the source code isn't run on the domains specified by [`vmDomainLock`](#vmdomainlock).
2376
2444
 
2377
- ### `strictMode`
2378
- Type: `boolean | null` Default: `null`
2379
-
2380
- Allows to specify how the obfuscator should treat code regarding JavaScript strict mode.
2381
-
2382
- Available values:
2383
- * `null` (default) - auto-detect strict mode from the code. If the code has explicit `'use strict'` directive, ES module syntax, or class methods, it's treated as strict mode. Otherwise, sloppy mode is assumed.
2384
- * `true` - force strict mode treatment for all code, even without explicit `'use strict'` directive. Use this when your code will run in strict mode context (e.g., in ES modules, bundlers, or modern frameworks).
2385
- * `false` - only explicit strict mode indicators (`'use strict'`, ES modules, class methods) are treated as strict. Parent scope inheritance still applies per JS spec.
2386
-
2387
- ### `parseHtml`
2388
- Type: `boolean` Default: `false`
2389
-
2390
- Enables obfuscation of JavaScript within HTML `<script>` tags.
2391
-
2392
- When enabled, the obfuscator will:
2393
- - Auto-detect if input is HTML (by checking for `<!DOCTYPE`, `<html>`, `<head>`, `<body>`, or `<script>` tags)
2394
- - Extract JavaScript from `<script>` tags marked with the `data-javascript-obfuscator` attribute
2395
- - Obfuscate each marked script individually while preserving the HTML structure
2396
- - Inject obfuscated code back into the original positions
2397
-
2398
- **Important:** Only scripts with the `data-javascript-obfuscator` attribute are obfuscated. Each marked script is obfuscated individually and independently. This means:
2399
- - Code inside marked script tags **must be isolated** - it must NOT reference variables, functions, or classes defined in other marked script tags
2400
- - Unmarked scripts can still access globals defined by marked scripts (via `var` declarations or explicit `globalThis` assignments)
2401
- - This gives you explicit control over which scripts to protect
2402
-
2403
- **Obfuscated (must have `data-javascript-obfuscator` attribute):**
2404
- - `<script data-javascript-obfuscator>` - regular scripts
2405
- - `<script type="text/javascript" data-javascript-obfuscator>` - explicitly typed scripts
2406
- - Scripts with any additional attributes (`id`, `class`, other `data-*`, etc.)
2407
-
2408
- **Skipped (left unchanged):**
2409
- - Scripts without `data-javascript-obfuscator` attribute
2410
- - `<script type="module">` - ES modules (even with the attribute)
2411
- - `<script src="...">` - external scripts (even with the attribute)
2412
- - Empty script tags
2413
-
2414
- **Note:** Source maps are not generated when `parseHtml` is enabled, as they would not map correctly to the HTML output.
2415
-
2416
- Example:
2417
- ```ts
2418
- // input
2419
- const html = `<!DOCTYPE html>
2420
- <html>
2421
- <body>
2422
- <!-- This script will NOT be obfuscated -->
2423
- <script>
2424
- var helper = 'utility';
2425
- </script>
2426
-
2427
- <!-- This script WILL be obfuscated -->
2428
- <script data-javascript-obfuscator>
2429
- var greeting = 'Hello World';
2430
- console.log(greeting);
2431
- </script>
2432
- </body>
2433
- </html>`;
2434
-
2435
- JavaScriptObfuscator.obfuscate(html, {
2436
- parseHtml: true,
2437
- stringArray: true
2438
- });
2439
-
2440
- // output: HTML with only the marked script obfuscated
2441
- ```
2442
-
2443
- ### `randomIdentifiersPrefix`
2444
- Type: `boolean` Default: `false`
2445
-
2446
- Appends a seeded random prefix (6 alphanumeric characters) to all global identifiers. Use this option to avoid collisions between separately obfuscated bundles that are loaded into the same global scope — it removes the need to pick a unique `identifiersPrefix` per bundle manually.
2447
-
2448
- - The random value is derived from the `seed` option and the source code hash, so reproducible builds with the same seed produce the same prefix.
2449
- - When combined with `identifiersPrefix`, the random characters are appended to the user-provided prefix (e.g. `myApp` + random `aBc123` → `myAppaBc123`).
2450
- - When combined with `vmObfuscation`, the random value replaces the default `vm` prefix — randomness already guarantees uniqueness.
2451
-
2452
2445
  ## Frequently Asked Questions
2453
2446
 
2454
2447
  ### What javascript versions are supported?