Conversation
Detects the calling AI coding agent from a hardcoded env-var allowlist and appends " agent/<id>" to the tilesets Session User-Agent when one is found. No server dependency: the header is already logged by CloudFront, and the agent's environment is directly visible to this CLI's subprocess.
- Reject fallback (AI_AGENT/AGENT) values outside a safe header charset so a stray newline/colon can no longer crash every CLI command with requests.exceptions.InvalidHeader. - Treat empty/whitespace-only harness env vars as unset, matching the fallback path's existing empty-value handling.
ctufts
commented
Sep 10, 2026
Per review feedback (#219, line 70), the fallback detector should only check whether AI_AGENT/AGENT is present, never read and forward its value - an arbitrary, unvalidated string should not become an "agent id" in production telemetry. Fold the fallback into the allowlist itself as its lowest-precedence entry, returning a fixed `custom-agent` id on presence instead of the variable's value. This also removes the charset/length validation that existed only to sanitize that value, since every returned id is now a fixed literal. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
OX Security reviewed this pull request — nothing to fix.
Branch |
The allowlist's presence-check branch (expected is None) required a non-empty, non-whitespace value, so an env var explicitly set to "" or whitespace was treated as unset. Per feedback, existence is all that should matter - whether the key is present at all, not what it's set to. Check membership directly instead of stripping and testing truthiness. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Every allowlist entry now tests presence only, never a value: collapse the table from (agent_id, [(env_var, expected_value_or_None), ...]) to a flat (agent_id, [env_var, ...]), and drop the equality-check branch in detect_agent entirely. The warp entry compared TERM_PROGRAM against "WarpTerminal" - dropped outright, since TERM_PROGRAM is set by most terminal emulators (iTerm2, Apple Terminal, VS Code, Hyper, ...), not just Warp, and an existence-only check on it would misidentify most terminal sessions. vtcode's VTCODE has no such collision risk and stays as a plain presence check. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Detects the calling AI coding agent (Claude Code, Codex, Cursor, etc.) from a hardcoded environment-variable allowlist and appends
agent/<id>to the tilesetsSessionUser-Agent header when a match is found. The header is unchanged if nothing matches.This doesn't change anything server-side or forward the environment: CloudFront already logs the User-Agent, and the agent's environment is already visible to this CLI's own subprocess.
agent_detect.py::detect_agent()checks about 22 harness-specific env vars in a fixed precedence order (most are presence-only checks;warpandvtcoderequire an exact value match), then falls back toAI_AGENT/AGENTif nothing else matched. That fallback is restricted to a safe charset so a stray value, like a newline, can't reach the header and breakrequests. The full environment is never read, logged, or transmitted, only the matched id.Tested with
pytest tests/test_agent_detect.py tests/test_utils.py(34 passing), plus a manual check of_get_session()'s header: a positive case (CLAUDECODE=1->.../<version> agent/claude-code) and a negative control (agent vars unset, header unchanged). This is a client-side header change with no server dependency, so there's no downstream or operational impact.