Two P1 fixes from the round 7 reviewer pass:
1. _ScrubbedEnvAsyncCodex no longer leaks secrets across overlapping
sessions.
The fallback env-scrub wrapper (used when the installed SDK build
does not accept AppServerConfig(env=...)) refcounts deleted env
vars under a shared lock so concurrent fan-out workers do not
restore Studio's secrets while a peer is still inside SDK startup.
The round 6 implementation enumerated keys to scrub via
_codex_sdk_env_override() which only returns keys currently in
os.environ. If wrapper A had already deleted HF_TOKEN before
wrapper B entered, B's overrides dict no longer contained HF_TOKEN,
B never bumped the refcount for it, and A's exit restored
HF_TOKEN into the process env while B was still running -- so
B's spawned codex app-server inherited the secret.
Round 7 fix: under the lock, the union of (a) the current
overrides dict and (b) every key still refcounted by an earlier
wrapper is the set of keys this session must scrub. Originals are
tracked module-level rather than per-instance so the last wrapper
to release a key always restores the right pre-scrub value
regardless of who first saw it. New regression test reproduces
the leak against the round 6 code (asserts refcount == 2 after
B enters; old code records 1) and locks the fix in.
2. Device-auth verification URL is now host-allowlisted.
The codex login --device-auth output parser pulled any https URL
matching /device, /activate, or /verify out of the CLI's stdout
and emitted it as a device_url event. The frontend rendered that
URL as an "Open verification page" CTA the user can click. A
compromised codex shim earlier on PATH could print
https://evil.example/activate?code=ABCD and Studio would surface
the phishing link verbatim, even though every other login output
line goes through a strict safe-vocabulary filter.
Round 7 fix: device_url events only fire for URLs whose host is
on a small allowlist (auth.openai.com / chatgpt.com over https).
Anything else is logged at warn and dropped. Tests cover the
known-good upstream URLs, several attacker patterns (lookalike
subdomains, http downgrade, javascript:), and garbage input.