child_env strips the OpenRouter key from the environment the interface hands its child, by name and by every alias carrying the value, with twenty-two tests behind it. The child then took it straight back.
The child is python -m aihawk, which is this same click group, and the first thing the group does is read .env from the directory it inherited. The key is in that file, because the README says to put it there. So the process that launches Firefox held it anyway, and invisible_playwright._session.build_env seeds the engine's environment from that process: measured against the published 0.68.2, the key arrives in the environment Firefox is launched with.
The product said so out loud and nobody was reading it. This line appears twice at startup, once per process:
env .env: OPENROUTER_API_KEY
and it names only what the file APPLIED, which is only what was not already there. The second copy is the child announcing that it had no key and has just given itself one.
runner.forget_key takes the key out of a live environment, and the server path in cli.main calls it for itself. Reading the environment rather than filtering the file is deliberate: a browser server has no use for a model key whoever started it, so somebody running uvx aihawk in a shell that exports one, or beside a .env that holds one, had the same exposure and was never told. One call covers the file, the export and any alias. What counts as the key is now runner.without_key, one function with two callers asking it from opposite ends.
Six tests, four of which could not have existed before, because every test in that file stopped at the handover. One spawns the real server as a subprocess and asks what it ended up with, reading its own stderr line rather than anything written for the test. One holds the other direction, that the INTERFACE still gets the key from .env: without it, "delete the key everywhere" passes everything else and the product cannot start.
Four known-bad inputs, all killed: the call removed, the call made unconditional, the report taken before the drop, and removal by exact name only.
Two smaller things fixed in passing. The module docstring claimed two xfail markers the file itself records as deleted, and said no test spawns the server. And these tests now restore os.environ, which is not tidiness: load_env_file sets variables monkeypatch never saw, and one left behind made the next test read an environment that already held it, so the file applied nothing and the failure pointed at the product; forget_key deletes by value, so a developer running the suite with a real OPENAI_API_KEY exported would have lost it.
This is not a leak to the network: Firefox does not send its environment anywhere. It is a defence this repository wrote on purpose, undone half a second after it ran.
Verified locally: 709 passed, ruff clean, invisible_core.english clean, check_content.py clean, and the version gate green against the real index.