Unit 9: AI features on websites · Lesson 1 of 3 · 20 min

What the widget sends

An AI help button is just a form that posts somewhere. The first question is where, and with what.

case file

DeepSeek exposed database

DeepSeek · 2025

In January 2025 researchers found publicly reachable DeepSeek databases that required no authentication. A log table held over a million entries, including plaintext chat history, API keys and backend details. DeepSeek secured them promptly after disclosure.

What went wrong

Internal databases were exposed to the internet without authentication, and they stored user prompts and secrets in plain text.

What would have stopped it

  • Never expose database ports publicly; keep them on private networks with authentication.
  • Scan your external attack surface continuously, including non-standard ports.
  • Avoid logging prompts and secrets in plain text; redact sensitive fields.

What defenders could have seen

  • Attack surface alerts for open database ports.
  • Database queries from unknown internet addresses.

sourceswiz.iobleepingcomputer.com

Whatever a widget sends, someone stores. Before judging the assistant's answers, find out what leaves the page and where it lands.

mission

You are
The analyst reviewing a new AI help widget.
Situation
The shop added a chat assistant to its help page. Before judging its answers, you check what the page sends and to which server.
Goal
Read the widget's client code and list every field and destination.
Hand in
The endpoint it posts to and the data it attaches.

An AI widget as a pneumatic pipe

01

Find the widget's script

learner@web-lab
curl -s http://127.0.0.1:8000/help | grep -oE '/static/[a-z-]+\.js'
/static/assistant.js

you should see The page loads one assistant script.

02

Read where it posts

learner@web-lab
curl -s http://127.0.0.1:8000/static/assistant.js | grep -E 'endpoint|apiKey|model'
  endpoint: "https://api.example-ai.com/v1/chat",
  apiKey: "sk-shop-live-4f9a2c71d0e85b36",
  model: "helper-small",
    model: cfg.model,
  const res = await fetch(cfg.endpoint, {
    headers: { "Content-Type": "application/json", "Authorization": "Bearer " + cfg.apiKey },

you should see A third-party endpoint and an API key sat in the page's JavaScript, readable by anyone.

03

Read what it attaches

learner@web-lab
curl -s http://127.0.0.1:8000/static/assistant.js | grep -E 'send[A-Z]|email|cart|location'
  sendPageUrl: true,
  sendCart: true,
  sendEmail: true
    page: cfg.sendPageUrl ? location.href : undefined,
    email: cfg.sendEmail ? window.shopUser.email : undefined,
    cart: cfg.sendCart ? window.shopUser.cart : undefined

you should see The widget attaches the page URL, the signed-in email and the cart to every message.

defender tip A key in client-side JavaScript is not a secret. Anyone can read it and spend against it. Calls to an AI provider belong on the server, behind the site's own endpoint.

04

Check the page's policy

learner@web-lab
curl -sI http://127.0.0.1:8000/help | grep -i content-security-policy
Content-Security-Policy: default-src 'self'; connect-src 'self' https://api.example-ai.com

you should see The connect-src directive lists the AI host, which is where the data goes.

Where the AI call belongs

Today
fetch("https://api.example-ai.com/v1/chat", {
  headers: { Authorization: "Bearer sk-shop-live-..." },
  body: { email, cart, page }
})

Key and personal data leave the browser for a third party.

Fix
fetch("/api/assistant", {
  body: { message }
})

The browser talks to the shop; the shop calls the AI with its own key.

What a defender takes away

  1. 1An AI widget is a form; find its endpoint and payload first.
  2. 2API keys in client code are public.
  3. 3Personal data should reach an AI provider through your server, not the browser.

Questions

0 of 3 solved

Answer each one from what you find on your lab machine.