October 23, 2026
Secure HTML Formatting in Oracle APEX Reports: Avoid Cross-Site Scripting (XSS)
Introduction
By Karepalliganesh
4 min read
Introduction
In Oracle APEX, developers often customize Interactive Reports and Classic Reports by adding HTML directly to SQL queries. For example, we may concatenate HTML tags to display colored status badges, icons, or formatted text.
To render the HTML, developers sometimes disable the Escape Special Characters setting for the report column.
This can introduce a security vulnerability when the report displays data submitted by public users. If untrusted input is rendered as HTML without proper escaping, a malicious user may be able to inject JavaScript that executes in another user's browser.
In this blog, we will look at a common implementation, understand its security risk, and see how to use the HTML Expression attribute to format report columns more safely.
1. The Example: A Public Feedback Form
Imagine an Oracle APEX application with two pages:
- Public feedback form: Visitors can submit their name and feedback without logging in.
- Admin feedback report: Administrators can view the submitted feedback in an Interactive Report.
The application works as expected when visitors enter normal text.
However, a visitor could submit HTML or JavaScript-related content instead of an ordinary feedback message. If the administrator's report renders that content without escaping, the browser may interpret it as markup or execute an event handler.
This is known as Cross-Site Scripting (XSS).
2. The Common Approach: HTML Inside the SQL Query
To customize the report layout, developers sometimes generate HTML directly in the SQL query.
For example, the query might look like this:
SELECT
FEEDBACK_ID,
'<div class="feedback-card">' ||
'<strong>' || VISITOR_NAME || '</strong>' ||
'<p>' || FEEDBACK_TEXT || '</p>' ||
'</div>' AS FEEDBACK_DISPLAY,
CREATED_ON
FROM PUBLIC_FEEDBACK
ORDER BY CREATED_ON DESC;SELECT
FEEDBACK_ID,
'<div class="feedback-card">' ||
'<strong>' || VISITOR_NAME || '</strong>' ||
'<p>' || FEEDBACK_TEXT || '</p>' ||
'</div>' AS FEEDBACK_DISPLAY,
CREATED_ON
FROM PUBLIC_FEEDBACK
ORDER BY CREATED_ON DESC;Here, the query combines the visitor's name and feedback with HTML markup to generate a custom card.
To render the generated markup, the developer may set Escape Special Characters to No for the FEEDBACK_DISPLAY column.
This is risky because the visitor's input is also included in the generated HTML without escaping.
These screenshots show the common implementation pattern that can introduce a security problem.
3. How an Attacker Could Exploit This
Instead of entering normal feedback, a malicious visitor could submit a payload such as:
<img src=x onerror=alert('XSS')><img src=x onerror=alert('XSS')>This example attempts to execute JavaScript when the browser fails to load the image.
If the submitted content is later included in an HTML response without proper escaping, the browser may interpret the input as HTML and execute the event handler.
In a real attack, the consequences could be more serious than a demonstration alert. Depending on the application and the victim's privileges, XSS could be used to manipulate page content or perform unauthorized actions in the victim's browser session.
The risk is not limited to public feedback forms. It can affect any application that displays untrusted data, including customer comments, support tickets, contact forms, and other user-submitted records.
4. The Safer Approach: Use HTML Expression
Instead of concatenating HTML into the SQL query, return the actual data from the query and configure the presentation separately in Page Designer.
For example, the SQL query can simply return the required columns:
SELECT
FEEDBACK_ID,
VISITOR_NAME,
FEEDBACK_TEXT,
CREATED_ON
FROM PUBLIC_FEEDBACK
ORDER BY CREATED_ON DESC;SELECT
FEEDBACK_ID,
VISITOR_NAME,
FEEDBACK_TEXT,
CREATED_ON
FROM PUBLIC_FEEDBACK
ORDER BY CREATED_ON DESC;The query now focuses on retrieving data rather than constructing the HTML layout.
Configure the HTML Expression
Open the existing report in Page Designer.
- Expand the report region's Columns node.
- Select the
VISITOR_NAMEcolumn. - Locate the HTML Expression setting.
- Add the following expression:
<strong>#VISITOR_NAME#</strong>
<div class="feedback-card">
<p>#FEEDBACK_TEXT#</p>
</div><strong>#VISITOR_NAME#</strong>
<div class="feedback-card">
<p>#FEEDBACK_TEXT#</p>
</div>
These settings let you maintain a custom layout while ensuring the dynamic user-provided values are treated as text.
5. Verify the Secure Output
Now revisit the report and inspect the same feedback record containing the test payload:
<img src=x onerror=alert('XSS')><img src=x onerror=alert('XSS')>With the HTML Expression configured to escape the substituted value, the browser should display the submitted content as text instead of interpreting it as an image element.
No JavaScript alert should appear.
The surrounding developer-defined HTML, such as the <div> and <p> tags, can still provide the intended layout.
6. Key Takeaways
- Avoid concatenating untrusted user input into HTML strings in SQL queries.
- Do not disable escaping simply to make custom HTML render.
- Use the HTML Expression attribute to separate presentation from query data.
HTML Expression is not automatically secure in every configuration. Its benefit comes from keeping the markup under the developer's control and correctly escaping dynamic values.
Conclusion
Custom report layouts are common in Oracle APEX applications, but security should not be overlooked when the report displays user-submitted data.
Concatenating HTML into SQL and disabling escaping can expose an application to XSS vulnerabilities. Using HTML Expression with properly escaped substitutions provides a safer way to customize report output.
The simple rule is: separate your data from your HTML, and never render untrusted user input as raw HTML.