HTML Tag Injection / Cross-Site Scripting (XSS): Explanation, Example, and Prevention

Quoc DangQuoc Dang
3 min read

❗ What is HTML Tag Injection / Cross-Site Scripting?

Cross-Site Scripting (XSS) or HTML Tag Injection is a type of security vulnerability that allows attackers to inject malicious scripts into web pages viewed by other users. When the application fails to properly sanitize user input, attackers can execute arbitrary JavaScript in the context of another user’s session.


πŸ’₯ Example: What Can Go Wrong?

Let’s say you have a blog comment section where users can submit comments. If you directly save user input and display it back, here’s what can happen:

<!-- User input saved as: -->
<script>alert('XSS attack!')</script>

If rendered unescaped in HTML, this will execute the JavaScript:

<p><script>alert('XSS attack!')</script></p>

Result? The browser executes it, and the user sees an alert. Worse, the script could steal cookies, redirect users, or deface the page.


πŸ” How to Prevent It (Clean Architecture Style)

βœ… Step 1: Use a Common Utility to Sanitize Input

We'll use Apache Commons Text in Java to escape dangerous characters like <, >, &, ", ', etc.

import org.apache.commons.text.StringEscapeUtils;

public class HtmlSanitizer {

    // Escape HTML special characters
    public static String sanitize(String input) {
        return StringEscapeUtils.escapeHtml4(input);
    }

    // Optional: Decode for rendering formatted content
    public static String unsanitize(String input) {
        return StringEscapeUtils.unescapeHtml4(input);
    }
}

Maven dependency:

<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-text</artifactId>
  <version>1.10.0</version>
</dependency>

βœ… Step 2: Sanitize Before Saving to Database

Apply the sanitize() method on every user input that will be stored:

@PostMapping("/comment")
public ResponseEntity<?> addComment(@RequestBody CommentRequest request) {
    String safeContent = HtmlSanitizer.sanitize(request.getContent());

    Comment comment = new Comment();
    comment.setContent(safeContent);
    commentRepository.save(comment);

    return ResponseEntity.ok("Saved");
}

βœ… Step 3: Display Safely in Frontend

Use a templating engine that escapes HTML by default (e.g., Thymeleaf, JSP):

<!-- Safe display -->
<p th:text="${comment.content}"></p>

If you really need to display formatted HTML (like markdown), decode it carefully:

<!-- Only do this if the data is fully trusted -->
<p th:utext="${T(HtmlSanitizer).unsanitize(comment.content)}"></p>

πŸ“Œ Summary: Do It Right

LayerPurposeWhat to do
Controller/InputSanitize dangerous charactersHtmlSanitizer.sanitize()
DB layerStore encoded safe contentAlready sanitized from input
UI layerEscape by default / decode if neededth:text or unsanitize()

πŸ” Real-World Tips

  • Never trust user input, even from authenticated users.

  • Always sanitize before storing in DB.

  • Use frameworks that escape content automatically.

  • For rich text or markdown, whitelist allowed tags.


βœ… Conclusion

HTML Tag Injection (XSS) is dangerous but easily preventable. Treat all inputs as untrusted, sanitize smartly, and render safely. Using a common utility ensures consistency across your entire app.

Stay secure and write safe code! πŸ‘¨β€πŸ’»πŸ§ 

0
Subscribe to my newsletter

Read articles from Quoc Dang directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Quoc Dang
Quoc Dang