Skip to content

CWE-80: Cross-Site Scripting (XSS) - Java

Overview

Cross-Site Scripting (CWE-80) occurs when untrusted data is included in web pages without proper encoding. Attackers inject malicious scripts that execute in victim browsers, leading to session theft, credential harvesting, or defacement. Java applications must encode all user-controlled output using context-appropriate methods.

Primary Defence: Use JSTL's <c:out> tag or framework-specific encoding (Spring's <spring:escapeBody>, Thymeleaf's default escaping) for all dynamic content in JSP/templates, use OWASP Java Encoder for context-specific encoding (Encode.forHtml(), Encode.forJavaScript(), Encode.forCssString()), never use raw EL expressions or scriptlets without encoding, implement Content Security Policy (CSP) headers, and validate input to prevent XSS attacks.

Common Vulnerable Patterns

Direct Output to JSP Without Encoding

<%-- VULNERABLE - scriptlet with no encoding --%>
<div>Welcome, <%= request.getParameter("username") %></div>

<%-- VULNERABLE - EL without c:out --%>
<p>Comment: ${param.comment}</p>

<%-- VULNERABLE - attribute without encoding --%>
<input type="text" value="<%= request.getParameter("search") %>">

Attack Examples:

username=<script>alert(document.cookie)</script>
comment=<img src=x onerror=alert('XSS')>
search="><script>alert(1)</script>

Servlet PrintWriter Without Encoding

// VULNERABLE - Direct output
public void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException {
    String name = request.getParameter("name");
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    out.println("<h1>Welcome " + name + "!</h1>");  // NO ENCODING
}

// VULNERABLE - StringBuilder concatenation
String comment = request.getParameter("comment");
StringBuilder html = new StringBuilder();
html.append("<div class='comment'>");
html.append(comment);  // NO ENCODING
html.append("</div>");
response.getWriter().write(html.toString());

JavaScript Context Without Encoding

// VULNERABLE - User data in JavaScript
String userName = request.getParameter("user");
out.println("<script>");
out.println("var currentUser = '" + userName + "';");  // NO JS ENCODING
out.println("</script>");

// Attack: user='; alert(document.cookie); //
// Result: var currentUser = ''; alert(document.cookie); //';

URL Context Without Encoding

// VULNERABLE - Unencoded URL parameters
String redirect = request.getParameter("returnUrl");
out.println("<a href=\"" + redirect + "\">Continue</a>");  // NO URL ENCODING

// Attack: returnUrl=javascript:alert('XSS')

Thymeleaf th:utext (Unescaped)

<!-- VULNERABLE - th:utext bypasses escaping -->
<div th:utext="${userInput}">Content</div>

<!-- VULNERABLE - Using raw HTML from user -->
<p th:utext="${request.getParameter('content')}"></p>

JSON Responses with Manual Construction

// VULNERABLE - Manual JSON construction
public void doGet(HttpServletRequest request, HttpServletResponse response) {
    String name = request.getParameter("name");
    String json = "{\"userName\":\"" + name + "\"}";
    response.setContentType("application/json");
    response.getWriter().write(json);  // NO ESCAPING
}

// Attack: name=test","admin":true,"x":"y
// Result: {"userName":"test","admin":true,"x":"y"}

Secure Patterns

JSTL c:out in JSP

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!-- SAFE - c:out auto-escapes HTML -->
<div>Welcome, <c:out value="${param.username}"/></div>

<!-- SAFE - Attribute context -->
<input type="text" value="<c:out value='${param.search}'/>"/>

<!-- SAFE - With default value -->
<p><c:out value="${user.bio}" default="No bio available"/></p>

<!-- SAFE - Disable escaping only for trusted content -->
<c:out value="${trustedHtml}" escapeXml="false"/>  <!-- USE WITH CAUTION -->

CRITICAL: The JSTL taglib must be available, either via:

  1. Per-file declaration (recommended): <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> at the top of each JSP
  2. Global web.xml configuration:

    web.xml
    <jsp-config>
        <taglib>
        <taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
        <taglib-location>/WEB-INF/tld/c.tld</taglib-location>
        </taglib>
    </jsp-config>
    
  3. Auto-discovery: Some containers auto-discover taglibs from JARs in WEB-INF/lib (unreliable, avoid)

Without any taglib configuration, <c:out> becomes literal text in the HTML output, but the EL expression ${param.username} still evaluates without escaping, creating an XSS vulnerability. Always use explicit per-file declarations for clarity and reliability.

Why this works: The <c:out> tag from JSTL automatically HTML-encodes all output by default (when escapeXml is true or unspecified), converting dangerous characters like <, >, &, ", and ' into their HTML entity equivalents (&lt;, &gt;, &amp;, &quot;, &#39;). This prevents browsers from interpreting user input as HTML markup or JavaScript code. The encoding happens at the output stage (not input), ensuring that even if malicious content like <script>alert(1)</script> is in the variable, it renders as plain text instead of executing. This is the recommended approach for JSP because it's built into the framework, works in both HTML body and attribute contexts, and cannot be accidentally bypassed unless you explicitly set escapeXml="false".

import org.owasp.encoder.Encode;

public void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException {

    String name = request.getParameter("name");
    String comment = request.getParameter("comment");

    response.setContentType("text/html; charset=UTF-8");
    PrintWriter out = response.getWriter();

    // SAFE - HTML context
    out.println("<h1>Welcome " + Encode.forHtml(name) + "!</h1>");

    // SAFE - HTML attribute context
    out.println("<div class=\"" + Encode.forHtmlAttribute(comment) + "\">");

    // SAFE - JavaScript context
    out.println("<script>");
    out.println("var user = '" + Encode.forJavaScript(name) + "';");
    out.println("</script>");

    // SAFE - URL context
    String search = request.getParameter("q");
    String url = "/search?q=" + Encode.forUriComponent(search);
    out.println("<a href=\"" + Encode.forHtmlAttribute(url) + "\">Search</a>");
}

Why this works: OWASP Java Encoder provides context-aware encoding methods that apply the correct transformations for each output context. Encode.forHtml() converts characters like <>\"'& to HTML entities, preventing tag injection in HTML body content. Encode.forHtmlAttribute() additionally handles quote escaping for safe use in attributes. Encode.forJavaScript() uses Unicode escaping (\\xHH or \\uHHHH) to neutralize special characters in JavaScript strings, preventing script injection even when user input contains quotes or control characters. Encode.forUriComponent() applies percent-encoding for URL parameters. Each method is specifically designed for its context, making it impossible for attackers to break out of the intended data context and inject malicious code. This library is battle-tested, actively maintained, and recommended by OWASP for production use.

Spring HtmlUtils

import org.springframework.web.util.HtmlUtils;

@GetMapping("/profile")
public String showProfile(@RequestParam String name, Model model) {
    // SAFE - Escape before adding to model
    String safeName = HtmlUtils.htmlEscape(name);
    model.addAttribute("userName", safeName);
    return "profile";
}

// Or in template:
<%@ page import="org.springframework.web.util.HtmlUtils" %>
<div><%= HtmlUtils.htmlEscape(request.getParameter("name")) %></div>

Why this works: Spring's HtmlUtils.htmlEscape() performs HTML entity encoding by converting special characters (<, >, &, ", ') into their HTML entity equivalents (&lt;, &gt;, &amp;, &quot;, &#39;). This transformation ensures that even if user input contains HTML tags or JavaScript, browsers will render it as plain text rather than interpreting it as executable code. The method is part of the Spring Framework's core utilities and is specifically designed for web output encoding. It handles both ISO-8859-1 and UTF-8 character sets correctly. When used in Spring MVC controllers, encoding the data before adding it to the model ensures that XSS payloads are neutralized before reaching the view layer, providing defense in depth even if the view template has vulnerabilities.

Thymeleaf (Spring Boot) - Auto-Escaping

<!-- SAFE - th:text auto-escapes -->
<div th:text="${userInput}">Default</div>

<!-- SAFE - Attribute binding -->
<input type="text" th:value="${searchTerm}"/>

<!-- SAFE - URL parameters -->
<a th:href="@{/search(q=${query})}">Search</a>

<!-- SAFE - Multiple attributes -->
<div th:attr="data-user=${userName}, data-id=${userId}"></div>

Why this works: Thymeleaf's th:text attribute automatically HTML-encodes all content before rendering, preventing XSS by converting dangerous characters to HTML entities. The th:attr and attribute-specific directives (like th:href, th:value) provide context-aware encoding: they ensure values are properly escaped for their specific context (HTML content, attributes, URLs, etc.). The @{...} URL syntax automatically encodes query parameters. This auto-escaping is enabled by default in Spring Boot and cannot be accidentally bypassed unless you explicitly use th:utext (unescaped text), making it a secure-by-default approach.

JSF (JavaServer Faces)

<!-- SAFE - h:outputText escapes by default -->
<h:outputText value="#{userBean.name}"/>

<!-- SAFE - escape=true (explicit) -->
<h:outputText value="#{userBean.comment}" escape="true"/>

<!-- SAFE - Input components auto-escape -->
<h:inputText value="#{userBean.search}"/>

Why this works: JavaServer Faces (JSF) components like <h:outputText> automatically HTML-encode output by default through their escape="true" attribute (which is the default behavior when escape is not specified). This built-in encoding converts special HTML characters to entities before rendering, preventing XSS. The encoding is context-aware and happens during the Render Response phase of the JSF lifecycle, ensuring that data bound via Expression Language (EL) like #{userBean.name} is always safe. JSF input components (<h:inputText>, <h:inputTextarea>, etc.) also automatically escape values when rendering, protecting against reflected XSS. This secure-by-default behavior makes JSF applications resistant to XSS as long as developers don't explicitly set escape="false" on user-controlled data.

Jackson for JSON (REST APIs)

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
public class UserController {

    @GetMapping("/api/user")
    public ResponseEntity<Map<String, String>> getUser(@RequestParam String name) {
        // SAFE - Jackson auto-escapes when serializing to JSON
        Map<String, String> response = new HashMap<>();
        response.put("name", name);  // No manual escaping needed
        response.put("timestamp", Instant.now().toString());

        return ResponseEntity.ok(response);  // SAFE JSON
    }

    // SAFE - Explicit content type enforcement
    @GetMapping(value = "/api/profile", produces = MediaType.APPLICATION_JSON_VALUE)
    public User getUserProfile(@RequestParam String id) {
        // produces ensures response is encoded as JSON
        // Jackson serialization provides automatic escaping
        User user = userService.findById(id);
        return user;  // Jackson handles escaping automatically
    }
}

// How it works:
// - Jackson serializes objects to JSON with proper escaping
// - produces = APPLICATION_JSON_VALUE forces JSON content type
// - Prevents content-type confusion attacks
// - User input like: name = "<script>alert(1)</script>"
//   becomes: {"name":"<script>alert(1)</script>"} (escaped in JSON)

Why this works: Jackson automatically escapes special characters when serializing Java objects to JSON, ensuring that values like <script> are encoded as \u003cscript\u003e or remain as literal strings within JSON. The critical security features are: (1) Content-Type is set to application/json, preventing browsers from interpreting the response as HTML, and (2) JSON string encoding escapes quotes and backslashes, preventing injection into JavaScript contexts. The produces = MediaType.APPLICATION_JSON_VALUE annotation enforces JSON content type, blocking attacks that try to trick the browser into rendering JSON as HTML. This makes REST APIs secure by default without manual encoding.

JAX-RS (Java EE/Jakarta EE)

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/api")
public class UserResource {

    // SAFE - @Produces forces JSON serialization
    @GET
    @Path("/user")
    @Produces(MediaType.APPLICATION_JSON)  // Ensures JSON encoding
    public User getUser(@QueryParam("name") String name) {
        // JSON-B or Jackson serializer provides automatic escaping
        User user = new User();
        user.setName(name);  // No manual escaping needed
        return user;
    }

    // SAFE - Explicit Response with JSON content type
    @POST
    @Path("/profile")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)  // Forces JSON output encoding
    public Response createProfile(UserRequest request) {
        Map<String, String> response = new HashMap<>();
        response.put("username", request.getUsername());
        response.put("status", "created");

        // JSON provider handles escaping automatically
        return Response.ok(response).build();
    }
}

// How it works:
// - @Produces(MediaType.APPLICATION_JSON) tells JAX-RS to use JSON serializer
// - JSON provider (Jackson, JSON-B, Gson) escapes special characters
// - Prevents XSS by ensuring output is valid, escaped JSON
// - Content-Type header set to application/json automatically

Why this works: The @Produces(MediaType.APPLICATION_JSON) annotation tells JAX-RS to serialize the return value as JSON using a JSON provider (Jackson, JSON-B, or Gson). These JSON libraries automatically escape special characters like quotes, backslashes, and control characters according to JSON specification. The annotation also sets the Content-Type: application/json header, which prevents browsers from interpreting the response as HTML. This combination ensures that even if user input contains <script> tags, they remain as literal strings in the JSON and are never executed as code. The approach is secure-by-default for REST APIs.

Context-Specific Encoding

Context-specific encoding ensures that user input is properly encoded based on where it appears in the output.

HTML Body Context

import org.owasp.encoder.Encode;

String userInput = getUserInput();
out.println("<p>" + Encode.forHtml(userInput) + "</p>");

HTML Attribute Context

String userInput = getUserInput();
out.println("<div class=\"" + Encode.forHtmlAttribute(userInput) + "\">");

JavaScript Context

String userName = getUserName();
out.println("<script>");
out.println("var currentUser = '" + Encode.forJavaScript(userName) + "';");
out.println("</script>");

URL Parameter Context

String searchTerm = getSearchTerm();
String url = "/search?q=" + Encode.forUriComponent(searchTerm);
out.println("<a href=\"" + Encode.forHtmlAttribute(url) + "\">Search</a>");

CSS Context (Avoid if Possible)

// WARNING: CSS context is complex - avoid user input in CSS
String color = getUserColor();
if (!color.matches("^[a-zA-Z0-9#]+$")) {
    throw new SecurityException("Invalid color");
}
out.println("<div style=\"color: " + color + "\">");

Why this works: Each output context (HTML body, attributes, JavaScript, URLs, CSS) has different parsing rules and special characters, requiring context-specific encoding. Using Encode.forHtml() in HTML body context converts <>\"'& to entities, preventing tag injection. Encode.forHtmlAttribute() handles both entity encoding and quote escaping for safe attribute values. Encode.forJavaScript() uses Unicode escape sequences (\\xHH) to neutralize special characters in JavaScript string literals, preventing quote-based injection like '; alert(1)//. Encode.forUriComponent() percent-encodes reserved URL characters to prevent breaking out of the parameter context. Using the wrong encoder (e.g., HTML encoding in JavaScript context) leaves vulnerabilities because each context interprets characters differently. Context-aware encoding is critical - HTML encoding alone won't protect JavaScript contexts where </script> can close a script tag even when HTML-encoded.

Alternative Encoding Libraries

While OWASP Java Encoder, Spring HtmlUtils, and framework-specific methods (JSTL, Thymeleaf, JSF) are recommended, these alternatives may be useful in specific contexts:

OWASP ESAPI Encoder (legacy applications):

import org.owasp.esapi.ESAPI;
String safe = ESAPI.encoder().encodeForHTML(userInput);
// Maven: org.owasp.esapi:esapi

Why this works: These alternative libraries provide XSS protection for applications where the primary recommended libraries are unavailable or incompatible. OWASP ESAPI offers comprehensive security controls including context-aware encoding methods, though it's considered legacy and has a heavier footprint than modern alternatives. Apache Commons Text provides XML-specific escaping useful for XML generation scenarios. Framework-specific utilities (GWT, Liferay, Android) are optimized for their respective platforms and integrate seamlessly with framework conventions. While these alternatives work, prefer OWASP Java Encoder or framework-native solutions when possible for better performance and maintenance.

Apache Commons Text (XML-focused):

import org.apache.commons.text.StringEscapeUtils;
String safeXml = StringEscapeUtils.escapeXml10(userInput);
// Maven: org.apache.commons:commons-text

Framework-Specific Utilities:

  • GWT: SafeHtmlUtils.htmlEscape(userInput)
  • Liferay: HtmlUtil.escape(userInput)
  • Android: Uri.encode(userInput)

Content Security Policy (CSP)

Servlet Filter

@WebFilter("/*")
public class CSPFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        httpResponse.setHeader("Content-Security-Policy",
            "default-src 'self'; " +
            "script-src 'self'; " +
            "style-src 'self'; " +
            "img-src 'self' https://trusted-cdn.com; " +
            "connect-src 'self'; " +
            "frame-ancestors 'none';"
        );

        chain.doFilter(request, response);
    }
}

Spring Security Configuration

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers()
            .contentSecurityPolicy("default-src 'self'; script-src 'self'")
            .and()
            .xssProtection()
            .and()
            .contentTypeOptions();
    }
}

Input Validation (Defense in Depth)

import org.owasp.validator.html.*;

public class InputValidator {

    public String validateUserInput(String input) {
        // Length check
        if (input.length() > 1000) {
            throw new IllegalArgumentException("Input too long");
        }

        // Allowlist pattern for specific use cases
        if (!input.matches("^[a-zA-Z0-9 .,!?'-]+$")) {
            throw new IllegalArgumentException("Invalid characters");
        }

        return input;
    }

    public String sanitizeHTML(String input) throws ScanException, PolicyException {
        // Use OWASP AntiSamy for rich HTML input
        Policy policy = Policy.getInstance(
            getClass().getResourceAsStream("/antisamy-policy.xml")
        );

        AntiSamy antiSamy = new AntiSamy();
        CleanResults results = antiSamy.scan(input, policy);

        return results.getCleanHTML();
    }
}

JSON/API Responses

Jackson (Automatic Escaping)

import com.fasterxml.jackson.databind.ObjectMapper;

@RestController
public class ApiController {

    @GetMapping("/api/user")
    public User getUser(@RequestParam String name) {
        User user = new User();
        user.setName(name);  // Jackson automatically escapes when serializing
        return user;  // SAFE - JSON is properly escaped
    }
}

Manual JSON Construction (Avoid)

// VULNERABLE - manual JSON construction
String json = "{\"name\":\"" + userName + "\"}";

// SAFE - use JSON library
ObjectMapper mapper = new ObjectMapper();
Map<String, String> data = new HashMap<>();
data.put("name", userName);
String json = mapper.writeValueAsString(data);

Verification and Detection

Security testing requires multiple approaches - unit tests alone are insufficient.

Static Application Security Testing (SAST)

Use automated tools to analyze code for missing or incorrect encoding:

Commercial Tools:

  • Checkmarx - Comprehensive XSS detection for Java web applications
  • Fortify Static Code Analyzer - Data flow analysis from sources to sinks
  • Veracode - Cloud-based static analysis for Java
  • Snyk Code - Developer-focused security scanning

Open Source Tools:

  • SonarQube - Free community edition with XSS detection
  • SpotBugs with Find Security Bugs plugin
  • Semgrep - Fast, customizable pattern matching

Dynamic Application Security Testing (DAST)

Test running applications for XSS:

  • OWASP ZAP - Free automated scanner
  • Burp Suite Professional - Industry-standard web security testing
  • Acunetix - Comprehensive XSS detection
  • Arachni - Open-source web application security scanner

Code Review Checklist

Manually verify:

  • All JSP output uses <c:out> or proper encoding
  • Every JSP file using <c:out> has the JSTL taglib declaration, or global web.xml declaration
  • No raw <%= %> scriptlets without encoding
  • Servlets use context-appropriate encoding (Encode.forHtml(), Encode.forJavaScript(), etc.) for rendering all untrusted input
  • Thymeleaf uses th:text (not th:utext) for user data
  • No escapeXml="false" on user input
  • Context-appropriate encoding (HTML vs JS vs URL vs CSS)
  • JSON responses use proper serialization libraries
  • All input sources identified (params, headers, cookies, database)

Framework-Specific Tools

Spring Boot:

# OWASP Dependency Check
mvn org.owasp:dependency-check-maven:check

# Spring Security audits
mvn spring-boot:run -Dspring-boot.run.arguments=--debug

JSP/Servlet:

# Check for unescaped output
grep -r "<%= " src/main/webapp/
grep -r "escapeXml=\"false\"" src/main/webapp/

# Check for c:out usage without taglib declaration
# (Find JSP files using <c:out> but missing the taglib)
find src/main/webapp -name "*.jsp" -exec sh -c \
  'grep -l "<c:out" "$1" | xargs grep -L "taglib.*jstl/core"' _ {} \;

Limited Role of Unit Tests

Manual verification with XSS payloads:

// Test these payloads in your application:
String[] xssPayloads = {
    "<script>alert('XSS')</script>",
    "<img src=x onerror=alert('XSS')>",
    "javascript:alert('XSS')",
    "<svg onload=alert('XSS')>",
    "'><script>alert(String.fromCharCode(88,83,83))</script>"
};

for (String payload : xssPayloads) {
    // Submit payload via form/API
    // View the rendered output in browser
    // Verify payload is HTML-encoded, NOT executed as script
    // Example: "<script>" should render as "&lt;script&gt;"
}

Verification steps:

  1. Check encoding library is used: Verify OWASP Java Encoder or framework escaping

    # Search for OWASP Encoder usage
    grep -r "Encode.forHtml\|Encode.forJavaScript" src/
    
    # For Thymeleaf, verify th:text (auto-escapes) not th:utext (raw)
    grep -r "th:utext" src/templates/
    # Should be minimal or zero - review each usage
    
  2. Browser DevTools verification: Inspect rendered HTML

    1. Submit XSS payload: <script>alert('XSS')</script>
    2. Open browser DevTools (F12) -> Elements tab
    3. Find where payload is rendered
    4. Verify it shows as text: &lt;script&gt;alert('XSS')&lt;/script&gt;
    5. NOT as executable script tag: <script>alert('XSS')</script>
  3. Content Security Policy check: Verify CSP headers block inline scripts

    # Check response headers
    curl -I https://yourapp.com
    # Should include:
    # Content-Security-Policy: default-src 'self'; script-src 'self'
    
  4. Static analysis: Use SAST tools to find XSS vulnerabilities

    # CodeQL: java/xss
    # SonarQube: S5146 (Template injection)
    # Semgrep: java.lang.security.audit.xss
    
    mvn sonar:sonar
    semgrep --config=p/xss src/
    
  5. DAST scanning: Use dynamic scanners to test running application

    # OWASP ZAP, Burp Suite, or similar
    # Configure to test XSS payloads
    # Review findings for reflected/stored XSS
    

Important: Unit tests verify encoding functions work but cannot ensure they're used everywhere. Manual code review and SAST/DAST are essential.

Continuous Security

  • CI/CD Integration - Run SAST in Jenkins/GitLab/GitHub Actions
  • Pre-commit Hooks - Prevent insecure code commits
  • Dependency Scanning - Monitor for vulnerable libraries
  • Security Champions - Train developers on secure coding
  • Penetration Testing - Periodic professional security assessments

Maven Dependencies

<!-- OWASP Java Encoder -->
<dependency>
    <groupId>org.owasp.encoder</groupId>
    <artifactId>encoder</artifactId>
</dependency>

<!-- OWASP Java HTML Sanitizer (for rich HTML) -->
<dependency>
    <groupId>com.googlecode.owasp-java-html-sanitizer</groupId>
    <artifactId>owasp-java-html-sanitizer</artifactId>
</dependency>

<!-- Spring Framework (if using Spring) -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
</dependency>

<!-- Apache Commons Text -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-text</artifactId>
</dependency>

Additional Resources