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.
| Input | Expected output | What it teaches |
|---|---|---|
<strong>Training note</strong> | The angle brackets and tag text remain visible | Input is not interpreted as formatting |
Research & practice | The original ampersand appears once | No unnecessary manual encoding |
| Two lines of fictional notes | Two visible text lines | Readable layout does not require HTML parsing |
| Whitespace only | A validation message and empty preview | Rejected 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.
Give links a different rule from ordinary text
A value used as a destination needs a URL decision, not just a text decision. The following local helper accepts absolute HTTPS addresses for a fictional resource-link field:
function approvedWebAddress(value) {
if (typeof value !== "string" || value.length > 300) return null;
try {
const url = new URL(value);
return url.protocol === "https:" ? url.href : null;
} catch {
return null;
}
}Try a valid HTTPS address, an ordinary sentence and an HTTP address. The latter two should be rejected under this exercise’s policy. If you later create a link, set its visible label using textContent and its destination only after validation. Prefer a fixed, known destination when the feature does not require user-supplied links.
This helper does not establish that the destination is honest or that its content is safe. It also is not a general file-upload, redirect or server-side fetch validator. Write those limitations beside the code so it is not reused for a different job without review.
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
- Gammal Tech API documentation
- OWASP XSS Prevention Cheat Sheet
- OWASP Third Party JavaScript Management
Documentation checked on 12 October 2026. Recheck current documentation before implementing or quoting a client project.