>
Software Security Training

Exercise: The Malicious Link

In this activity, you will prevent Context-Aware XSS by validating URLs.

Scenario: Your site allows users to set a "Website URL" on their profile. The code places it here: <a href="{url}">.

A hacker entered: javascript:alert(1). When anyone clicks their profile link, the script executes!

Your Task

Modify the sanitize_link function:

  1. Protocol Check: Ensure the URL starts with http:// or https://.
  2. Reject Bad Input: If it doesn't match, return a safe default: "#".
  3. Sanitize: Even if the protocol is good, use html.escape() to prevent "quote breaking" attacks (e.g., https://x.com" onclick="alert(1)).

Why This Matters

html.escape() alone is not enough here. A malicious JavaScript URL is valid HTML text, but dangerous when used in an href context. You must allowlist the protocol first.

PYTHON EDITOR (profile_module.py) Engine: Initializing...
1
BROWSER CONSOLE OUTPUT
Ready... Waiting for link simulation.
from js import window # Signal that Python is alive window.python_is_ready = True # Update the UI try: document = window.document status = document.getElementById("engine-status") status.innerHTML = "Engine: Python Active" except: pass import html def python_test_logic(user_code): results = [] # Helper to log results back to JS def add_log(msg, type="normal"): results.append({"msg": msg, "type": type}) add_log("[SYSTEM] Running tests via Python Engine...", "system") test_env = {'html': html} try: exec(user_code, test_env) if "sanitize_link" not in test_env: add_log("[!] Error: Function 'sanitize_link' not found.", "fail") return results, "FAILED" sanitize_link = test_env["sanitize_link"] # TEST 1 add_log("--- TEST 1: Normal HTTPS Link ---", "system") val_in = "https://google.com" res1 = sanitize_link(val_in) if res1 == val_in: add_log(" -> PASS: Valid HTTPS link allowed.", "pass") else: add_log(f" -> FAIL: Valid link blocked. Got: {res1}", "fail") return results, "FAILED" # TEST 2 add_log("--- TEST 2: Javascript Protocol Attack ---", "system") mal_in = "javascript:alert(1)" res2 = sanitize_link(mal_in) if res2 == "#": add_log(" -> PASS: Malicious protocol blocked.", "pass") elif res2 == mal_in: add_log(" -> FAIL: VULNERABILITY! 'javascript:' allowed.", "fail") return results, "FAILED" else: add_log(f" -> FAIL: Expected '#', got '{res2}'", "fail") return results, "FAILED" # TEST 3 add_log("--- TEST 3: Attribute Breakout Attack ---", "system") break_in = 'https://site.com" onclick="alert(1)' res3 = sanitize_link(break_in) if '"' in res3: add_log(" -> FAIL: Quotes were NOT escaped!", "fail") return results, "FAILED" elif res3.startswith("https://") and (""" in res3 or "'" in res3): add_log(" -> PASS: Dangerous characters escaped.", "pass") add_log(" SUCCESS: Context-Aware Sanitization Complete!", "pass") return results, "PASSED" elif res3 == "#": add_log(" -> PASS: Blocked entirely (Safe).", "pass") return results, "PASSED" else: add_log(f" -> FAIL: Unexpected output: {res3}", "fail") return results, "FAILED" except Exception as e: add_log(f"[!] Runtime Error: {e}", "fail") return results, "ERROR" return results, "UNKNOWN" # Expose to JS window.python_test_runner = python_test_logic