Annotation Interface XssCheck
By default, the OG4Dev Spring API Response library does NOT perform XSS validation on strings. This annotation allows you to opt-in to automatic HTML/XML tag detection and rejection for specific fields or entire classes where preventing malicious content injection is critical for security.
Security Approach: This annotation implements a fail-fast rejection strategy - requests containing HTML tags are rejected entirely with a 400 Bad Request error. This is more secure than HTML escaping, as it prevents stored XSS, DOM-based XSS, and second-order injection vulnerabilities.
Target Scopes
- Field Level (
ElementType.FIELD): Applies XSS validation only to the specific annotated String field. - Class Level (
ElementType.TYPE): Applies XSS validation to all String fields within the annotated class globally.
Example Usage: Field Level
public class CommentDTO {
@XssCheck
private String content; // XSS validated - rejects HTML tags
@XssCheck
private String authorName; // XSS validated - rejects HTML tags
private String commentId; // NOT validated (no annotation)
private Instant timestamp; // NOT validated (not a string)
}
Example Usage: Class Level
@XssCheck // Automatically protects ALL String fields in this class!
public class SecureUserProfileDTO {
private String bio; // XSS validated automatically
private String displayName; // XSS validated automatically
private String websiteUrl; // XSS validated automatically
}
Valid and Invalid Inputs
// ✅ Valid inputs (accepted)
{"content": "Hello World"} // Plain text
{"content": "Price: $100 < $200"} // Comparison operators (no tag)
{"content": "2 + 2 = 4"} // Math expressions
{"content": "Use angle brackets: 3 < 5"} // Text with < but no HTML tag
// ❌ Invalid inputs (rejected with 400 Bad Request)
{"content": "<script>alert('XSS')</script>"} // Script injection
{"content": "<img src=x onerror=alert(1)>"} // Image XSS attack
{"content": "Hello<br>World"} // HTML break tag
{"content": ""} // HTML comment
{"content": "<!DOCTYPE html>"} // DOCTYPE declaration
{"content": "</div>"} // Closing tag
{"content": "<b>Bold text</b>"} // HTML formatting
Error Response Format
When HTML tags are detected, the request is rejected with a 400 Bad Request error:
{
"type": "about:blank",
"title": "Bad Request",
"status": 400,
"detail": "Security Error: HTML tags or XSS payloads are not allowed in the request.",
"traceId": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2026-02-21T10:30:45.123Z"
}
XSS Detection Mechanism
The validation uses a robust regex pattern: (?s).*<\s*[a-zA-Z/!].*
This pattern detects:
- Opening tags:
<script>,<img>,<div>,<iframe> - Closing tags:
</div>,</script>,</body> - Self-closing tags:
<br/>,<input/> - Special tags:
<!DOCTYPE>, ,<![CDATA[]]> - Tags with attributes:
<div class="test">,<img src="x"> - Multiline tags: Tags spanning multiple lines (DOTALL mode enabled)
What is NOT detected (safe to use):
- Mathematical comparisons:
5 < 10,x > y - Arrows and symbols:
-> <-,<=> - Quoted examples:
"less than symbol: <"(if properly escaped in JSON)
Why Rejection Instead of Escaping?
This library uses a fail-fast rejection approach rather than HTML escaping (converting < to <).
This is more secure because:
- Prevents stored XSS: Malicious content never enters your database
- Prevents DOM-based XSS: No chance of client-side re-interpretation
- Prevents second-order attacks: Escaped content cannot be un-escaped later
- Prevents encoding bypasses: No risk of double-encoding vulnerabilities
- Clear security policy: Users know HTML is not allowed
Combining with @AutoTrim
You can combine @XssCheck with @AutoTrim for both behaviors:
@XssCheck // Protects all fields
public class SecureInputDTO {
@AutoTrim // Trims only this field
private String username;
}
How It Works
This annotation is processed by the AdvancedStringDeserializer in
ApiResponseAutoConfiguration.strictJsonCustomizer().
The deserializer uses ValueDeserializer.createContextual(tools.jackson.databind.DeserializationContext, tools.jackson.databind.BeanProperty)
to detect the annotation on either the field itself or its declaring class, creating a
specialized instance that enables XSS validation.
Null Value Handling
Null values are not validated (they are safe) and pass through unchanged:
{"content": null} → content = null (no validation)
{"content": ""} → content = "" (validated, but empty string is safe)
{"content": " "} → content = " " (validated, but whitespace is safe)
Performance Considerations
The regex validation is highly optimized and adds minimal overhead (typically <1ms
per field). The deserializer is created once per field during mapper initialization,
not on every request, ensuring optimal runtime performance.
When to Use This Annotation
| Field Type | Use @XssCheck? | Reason |
|---|---|---|
| User comments | ✅ Yes | User-generated content that will be displayed |
| Profile bio | ✅ Yes | Free-form text that could contain malicious content |
| Search queries | ✅ Yes | User input that might be echoed back |
| Email address | ⚠️ Optional | Use if email will be displayed; skip if only stored |
| IDs/UUIDs | ❌ No | Structured format, not free-form text |
| Timestamps | ❌ No | Not a string field |
| Rich text (HTML editor) | ❌ No | Intentionally contains HTML; use server-side sanitization instead |
- Since:
- 1.3.0
- Version:
- 1.4.0
- Author:
- Pasindu OG
- See Also:
-
ApiResponseAutoConfiguration.strictJsonCustomizer()AutoTrimValueDeserializer.createContextual(tools.jackson.databind.DeserializationContext, tools.jackson.databind.BeanProperty)