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
Find the widget's script
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.
Read where it posts
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.
Read what it attaches
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.
Check the page's policy
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
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.
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
- 1An AI widget is a form; find its endpoint and payload first.
- 2API keys in client code are public.
- 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.