diff --git a/src/pentesting-web/xs-search/url-max-length-client-side.md b/src/pentesting-web/xs-search/url-max-length-client-side.md
index 5d77303262e..445ced9cf7d 100644
--- a/src/pentesting-web/xs-search/url-max-length-client-side.md
+++ b/src/pentesting-web/xs-search/url-max-length-client-side.md
@@ -2,7 +2,30 @@
{{#include ../../banners/hacktricks-training.md}}
-This historical XS-Leak technique exploits Chrome's 2 MiB URL limit. The attacker opens a URL just below the limit. If a secret-dependent response redirects to a longer URL, Chrome blocks the navigation and leaves an accessible `about:blank` document; otherwise, the window completes a cross-origin navigation and reading `origin` throws an exception. This difference provides a one-bit oracle.[[1]](#references)[[2]](#references)
+This Chromium-specific XS-Leak exploits the browser's 2 MiB URL limit. The attacker opens a URL just below the limit. If a secret-dependent response redirects to a longer URL, Chromium blocks the navigation and leaves an accessible `about:blank` document; otherwise, the window completes a cross-origin navigation and reading `origin` throws an exception. This difference provides a one-bit oracle.[[1]](#references)[[2]](#references)
+
+## Requirements and mechanics
+
+The useful gadget is a **credentialed top-level GET** whose hit and miss paths produce final URLs of different lengths. This matters because `SameSite=Lax` cookies can accompany a top-level navigation even though they would normally be absent from a cross-site subresource probe. The attacker must also retain the popup's `WindowProxy`, and the ordinary branch must commit a document cross-origin from the attacker.[[1]](#references)
+
+The padding belongs in the **fragment**. It is not sent in the HTTP request, so the initial request does not have to cross a server or proxy request-line limit. When an HTTP redirect has no fragment of its own, the browser carries the original fragment into the redirect target; any state-dependent path/query growth can therefore push only the final client-side URL over the limit. A `Location` containing its own fragment replaces this padding and breaks the primitive.[[1]](#references)
+
+Current Chromium keeps `kMaxURLChars` at `2 * 1024 * 1024` (2,097,152) and rejects a navigation when the canonical destination's `spec().size()` is greater than that value. Count the **serialized URL**, not an unescaped input string: percent-encoding and URL canonicalization can change its size. Using an ASCII fragment makes the calculation predictable.[[2]](#references)[[3]](#references)
+
+```javascript
+function padBelowLimit(base, slack = 1) {
+ const u = new URL(base)
+ u.hash = ""
+ const head = u.href + "#"
+ const count = 2 * 1024 * 1024 - head.length - slack
+ if (count < 0) throw new Error("base URL already exceeds the limit")
+ return head + "A".repeat(count)
+}
+```
+
+Choose `slack` smaller than the redirect-induced growth, and calibrate the boundary with known hit/miss queries in the exact browser build. Do not assume that every oversized navigation exposes the same state: current Chromium regression tests map an oversized fragment from an initial `about:blank` document to `about:blank#blocked`, while an oversized same-document fragment navigation from an already committed non-blank page can retain its previous URL. The fresh popup/initial-document state is therefore part of the gadget.[[3]](#references)[[4]](#references)
+
+## Proof of concept
The following proof of concept, adapted from the HackTM CTF 2023 write-up, tests candidate characters:[[1]](#references)
@@ -74,9 +97,20 @@ if __name__ == '__main__':
app.run(host='0.0.0.0', port=1337)
```
+This PoC is an **elimination oracle**: a `SecurityError` means the popup committed cross-origin, so that candidate is reported as `nope`; candidates that remain readable are possible hits. The initial popup is also readable before its navigation commits, so never classify the first successful read as a hit. Use a bounded polling deadline, reject `window.open()` returning `null`, close each popup, keep concurrency low, and confirm survivors over several runs with known positive and negative controls. Otherwise slow navigation, popup blocking, or the memory cost of multiple 2 MiB URLs can create false positives and destabilize a browser bot.[[1]](#references)
+
+## Limitations and defenses
+
+This is not a generic URL-length oracle: it requires a length-changing redirect, inherited fragment padding, a usable top-level popup, and Chromium behavior that preserves a same-origin initial document on the oversized branch. Firefox, WebKit, embedded WebViews, and future Chromium versions must be measured independently rather than assigned the same threshold or blocked-page behavior.[[1]](#references)[[4]](#references)
+
+The strongest fix is to remove the state-dependent navigation difference: do not place secret-dependent data in redirect destinations and make hit/miss redirects indistinguishable in structure and length.[[1]](#references) See the general [XS-Leaks defenses](README.md#defenses) for controls that restrict credentialed cross-site requests or sever opener relationships.
+
+
+
## References
- [1] [HackTM CTF Quals 2023 - secrets (unintended solution: Chrome's 2MB URL limit)](https://ctf.zeyu2001.com/2023/hacktm-ctf-qualifiers/secrets#unintended-solution-chromes-2mb-url-limit)
- [2] [Chromium - URL display guidelines: URL length](https://chromium.googlesource.com/chromium/src/+/main/docs/security/url_display_guidelines/url_display_guidelines.md#URL-Length)
-
+- [3] [Chromium - navigation URL validation (`kMaxURLChars`)](https://chromium.googlesource.com/chromium/src/+/main/content/browser/renderer_host/navigation_controller_impl.cc)
+- [4] [Chromium - oversized navigation browser tests](https://chromium.googlesource.com/chromium/src/+/main/content/browser/navigation_browsertest.cc)
{{#include ../../banners/hacktricks-training.md}}