What you will learn

Build a local preview that displays user input as text, including harmless markup characters. Then apply the same rule to a fictional AI answer and explain why a browser form check cannot enforce a business permission. This lab produces a small safe-display component and an evidence table before you connect it to a hosted API.

Start with a local exercise that sends nothing

You need a text editor, a browser and basic familiarity with an HTML element and a JavaScript event listener. No Gammal Tech account or paid AI call is required for the first exercise. Use a page you own and fictional text. The examples are code to place in your learning file, not controls you can operate inside this article.

Create one HTML page with the following elements. Place your JavaScript after them or load it only after the document elements exist:

<label for="lab-note">Fictional learning note</label>
<textarea id="lab-note" maxlength="300"></textarea>
<button id="preview-note" type="button">Preview locally</button>
<p id="preview-status" role="status"></p>
<pre id="safe-output"></pre>

The preview area is an ordinary pre element. It preserves visible line breaks while the JavaScript decides how to supply the content. The offline version separates display behavior from authentication and billing.

Implement one deliberate text path

OWASP’s XSS prevention guide recommends safe output handling appropriate to the display context. For this ordinary text element, assign the original string through textContent; do not build an HTML string from the note.

const note = document.getElementById("lab-note");
const preview = document.getElementById("preview-note");
const status = document.getElementById("preview-status");
const output = document.getElementById("safe-output");
preview.addEventListener("click", () => {
  const value = note.value;
  if (value.trim().length === 0 || value.length > 300) {
    status.textContent = "Enter 1 to 300 characters.";
    output.textContent = "";
    return;
  }
  output.textContent = value;
  status.textContent = "Local text preview. Nothing was sent.";
});

The validation branch clears an earlier preview so a rejected new input does not leave the old output looking like a successful update. Status messages are also written as text. The example avoids logging entered content or exceptions. Do not pre-encode the input before assigning it as text, because that would make HTML entity spellings appear instead of the original characters.

Test characters that reveal interpretation

Enter the following harmless examples and write what you expect before pressing Preview. You are checking display behavior, not trying to attack another site.

Local safe-display acceptance cases
InputExpected outputWhat it teaches
<strong>Training note</strong>The angle brackets and tag text remain visibleInput is not interpreted as formatting
Research & practiceThe original ampersand appears onceNo unnecessary manual encoding
Two lines of fictional notesTwo visible text linesReadable layout does not require HTML parsing
Whitespace onlyA validation message and empty previewRejected input does not masquerade as a success

Also test Arabic text and the maximum permitted length. Record the browser and file version. These results cover this component, not the whole website.

Treat a fictional AI answer the same way

A generated answer can contain markup, links or code-like text. For this local demonstration, use a fixed fixture rather than calling an AI service:

// A fictional local fixture, not a response from a live AI call.
const fictionalAnswer = "<strong>Check the project settings</strong>";
output.textContent = fictionalAnswer;

The output should show the literal tag text, not a bold instruction. Label the demonstration “fictional answer fixture” in your portfolio so nobody mistakes it for a live service test. Later, when integrating a documented AI call, keep the returned string on this text-rendering path and add the appropriate request and failure states.

If the product needs rich formatting, that is a separate feature with an explicit permitted format and a maintained sanitization process. Do not quietly replace textContent with innerHTML to make one answer look nicer. A public prompt is not a browser security control.

Separate helpful form checks from trusted enforcement

The textarea length and JavaScript checks make the interface clearer, but a person controls their own browser. They can alter local form values or bypass the button. Therefore a frontend check cannot independently enforce account permissions, payment status, product prices or service quotas.

Draw three boxes on paper: browser, hosted API and any existing trusted business system. Put text preview in the browser box. Put a paid-access decision in the component that can verify the relevant authority. If you cannot identify such a component for a promised feature, mark the design incomplete. Do not “fix” it by hiding a field or obfuscating JavaScript.

Your deliverable should say what the frontend validates for usability and which decisions require trusted enforcement. This distinction is a core cybersecurity skill that applies even to a visually simple website.

Protect the code that reaches the browser

Gammal Tech can host supported login and user-data functions, while your frontend still displays returned information. A malicious change to that frontend may affect the data and actions available to the page. Protect the domain, deployment and repository accounts accordingly.

OWASP’s third-party JavaScript guidance explains why embedded scripts deserve review. Inventory each analytics or widget script in your learning project, record its purpose and remove unnecessary ones. An approved domain does not turn every script published there into trusted code. Ask who can add a new script and who reviews that change before a client site receives it.

Package the component with a short review note

Submit your single learning page, the acceptance table with actual results, the fictional AI fixture and the three-box responsibility sketch. Include one failed case you handled correctly and explain why the preview was cleared. Identify whether the page stayed local or was deployed to a domain you control.

For acceptance, ordinary and AI fixture text must remain literal, links must follow the stated policy, invalid input must show an honest state and no request should be made by this local lab. List the next review triggered by rich text, a new widget or live API integration. This exercise does not certify the application.

Common questions

Do I need to call the AI API to complete this lab?

No. The exercise uses an explicitly fictional local answer. It tests the display path without network calls or usage charges.

Does textContent solve every frontend security problem?

No. It is appropriate here for ordinary text elements. URL destinations, rich HTML, publishing access and business permissions require their own suitable controls.

Lesson references

Documentation checked on 12 October 2026. Recheck current documentation before implementing or quoting a client project.

Start your Gammal Tech exercise

Read the lesson, then practise with fictional data on a site you own or are authorized to use. Use your own verified individual account and open Developer Mode to configure your project. While awaiting verification, start with the data map and test plan.

Back to Articles & Guides