[ norboten ]
automation · lab ai-02

The Chatbot That Leaks Its Key

· about 40 minutes · runs on ubuntu-26.04-automation · unrated

An unrated lab. It runs on your machine with no account and no network, and everything about it — the faults, the checks, the hints and the reference solution — is in the repository. An attempt on it is recorded on your profile and never moves a rating: only rated labs do. Rated and unrated labs.

The briefing

chat-gateway is the internal front door to the model API: colleagues post a prompt to http://127.0.0.1:8090/ask through nginx, and the gateway calls the upstream model service with the company's API key.

The security review came back with four findings:

  • The upstream key sits in a world-readable file and in the systemd unit, where any account can read it with systemctl show.
  • Anyone who can reach port 8090 can use the gateway. It asks for nothing.
  • One script in a loop can spend the whole month's budget: there is no rate limit.
  • The gateway logs every request's headers, so both the upstream key and clients' tokens end up in the journal.

Client tokens are in /etc/chat-gateway/clients.token (one token, the first line). The gateway reads its settings from /etc/chat-gateway/gateway.env; it understands UPSTREAM_KEY_FILE, REQUIRE_TOKEN and LOG_HEADERS, and it also accepts the key as a systemd credential named upstream_key.

What is expected, and graded:

  1. The upstream key is not part of the unit definition — not in Environment=, not on the ExecStart line.
  2. The file holding it is readable only by the gateway's own account.
  3. A request without the client token gets 401; with it, 200.
  4. A burst of requests through nginx gets rejected with 429 before it reaches the model.
  5. Since the gateway last started, its journal contains neither the upstream key nor a client token.

You have root through sudo. Everything must still hold after a reboot.

What is graded

The machine is checked, rebooted, and checked again. A check passes only if it passes both times.

CheckObjective
01_key_not_in_the_unitKeep an upstream API key out of unit files and out of other accounts' reach
02_key_file_privateKeep an upstream API key out of unit files and out of other accounts' reach
03_gateway_requires_a_tokenRequire authentication on an internal AI gateway
04_bursts_are_rate_limitedRate-limit an expensive endpoint at the proxy
05_logs_have_no_secretsKeep secrets out of the logs

Start it

  1. 2Labs
  2. ai-02select this one
  3. udownload it
  4. sstart the machine

Reading

Where the lab's hints send you, level by level, as you ask for them (h, then l opens a journal section in the TUI).

Theory for this lab

4 questions on the same topic, in the lab's Theory tab. They never affect the lab's grade. Three of them, to answer here:

Question 1

An API key is in a unit's Environment= line. Which command lets any unprivileged user on the machine read it?

Question 2

What does LoadCredential= give a service that EnvironmentFile= does not?

Question 3

nginx rate limiting is set with `limit_req zone=chat burst=5 nodelay`. What status do rejected requests get unless `limit_req_status` says otherwise?