# Best practice for ClientID when using Codex OAuth

**URL:** <https://community.openai.com/t/best-practice-for-clientid-when-using-codex-oauth/1371778>\
**Category:** API\
**Created:** [January 16, 2026, 3:16am UTC](https://community.openai.com/t/best-practice-for-clientid-when-using-codex-oauth/1371778 "2026-01-16T03:16:44Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![sam.saffron](https://sea2.discourse-cdn.com/openai1/user_avatar/community.openai.com/sam.saffron/32/31387_2.png) [@sam.saffron](https://community.openai.com/u/sam.saffron)\
**Post date:** [January 16, 2026, 3:16am UTC](https://community.openai.com/t/best-practice-for-clientid-when-using-codex-oauth/1371778/1 "2026-01-16T03:16:44Z")

</div>

Over the past few hours Open AI announced a partnership with [roo-code.](https://roocode.com/)

> <https://x.com/roocode/status/2011962857043226780?s=20>

I decided to try it out with term-llm and it turns out it is trivial to implement.

> <https://github.com/SamSaffron/term-llm/blob/81fd0aeab12b89b27a0c89276813eb6a2a8b99ce/internal/oauth/chatgpt.go>

It works **perfectly** and now term-llm can have its very own oauth token it is responsible for. This is amazing.

What more… **this API is unlocked**

You no longer need a very particular developer message, this is enormous for sub-agents that want to act in very particular ways:

 ![image](https://us1.discourse-cdn.com/openai1/original/4X/a/5/8/a5874ba6847b8dea20eb5186c70a941abc3226dc.png)

The one snag here though is that consumers of the OpenAI OAuth bridge need to specify a ClientID.

At the moment both Roo Code and Codex reuse “app\_EMoa…”

Should other 3rd parties just piggy back on this?

🤗

---

<div class="post-metadata">

**Author:** ![sam.saffron](https://sea2.discourse-cdn.com/openai1/user_avatar/community.openai.com/sam.saffron/32/31387_2.png) [@sam.saffron](https://community.openai.com/u/sam.saffron)\
**Post date:** [January 16, 2026, 3:29am UTC](https://community.openai.com/t/best-practice-for-clientid-when-using-codex-oauth/1371778/2 "2026-01-16T03:29:13Z")

</div>

FWIW, a “non toy” workflow:

`term-llm ask --provider chatgpt:gpt-5.2-codex -m “You are an advanced security researcher who reviews repositories for flaws” --tools all --read-dir . perform a comprehnsive review of term-llm in which is in this directory --max-turns 200`

> ● glob (**/\* in .)  
> ● read\_file (/home/sam/Source/term-llm/AGENTS.md:1-200)  
> ● read\_file (/home/sam/Source/term-llm/internal/tools/permissions.go:1-200)  
> ● shell (ls -la /home/sam/Source/term-llm)  
> ● grep (/exec.Command|exec.Command…/ in /home/sam/Source/term-llm (**/\*.go))  
> ● read\_file (/home/sam/Source/term-llm/internal/tools/permissions.go:1-220)  
> ● shell (ls)  
> ● read\_file (/home/sam/Source/term-llm/internal/tools/permissions.go:1-260)  
> ● shell (rg -n "exec.Command|CommandContext|http.Clien…)  
> ● read\_file (/home/sam/Source/term-llm/internal/tools/approval.go:240-260)  
> ● read\_file (/home/sam/Source/term-llm/internal/tools/approval.go:240-260)  
> ● read\_file (/home/sam/Source/term-llm/internal/update/upgrade.go:1-240)
> 
> Below is a security-focused review of the term-llm repository. I focused on tool execution,  
> configuration resolution, update/download flows, and external request handling. Findings  
> include concrete risks, evidence, and actionable mitigations.
> 
> * * *
> 
> ## Summary
> 
> term-llm is a CLI that exposes powerful local tools (read/write/edit/shell, etc.), supports  
> multiple LLM providers, and can auto-update itself. The design includes explicit approvals  
> and allowlists, which is good, but there are several areas where trust boundaries can be  
> crossed or where untrusted input can reach command execution or network requests without  
> sufficient validation. The most significant risks are:
> 
> • Command execution from config values (shell evaluation).  
> • Command execution via shell tool approval model (approval bypass patterns and non‑TTY  
> execution).  
> • Unverified binary upgrade downloads (no signature/hash verification).  
> • SSRF-style URL fetching in some tools/providers without strict allowlisting.
> 
> * * *
> 
> ## High Severity Findings
> 
> ### 1) Config values allow arbitrary shell execution
> 
> Evidence: internal/config/resolve.go
> 
> case strings.HasPrefix(value, “$(”) && strings.HasSuffix(value, “)”):  
> return resolveCommand(value[2 : len(value)-1])  
> …  
> func resolveCommand(cmd string) (string, error) {  
> output, err := exec.Command(“sh”, “-c”, cmd).Output()
> 
> Risk: Any config value can embed $(…) and will execute arbitrary shell commands when  
> config is loaded. This turns configuration into an execution vector. If configuration can be  
> influenced (user, automation, malicious file in repo or homedir, or supply chain), it  
> becomes a trivial local RCE.
> 
> Mitigations:
> 
> • Remove $(…) support entirely or gate it behind an explicit opt‑in flag/environment  
> variable.  
> • If kept, restrict to a safe allowlist of commands or run via exec.Command with args, not  
> sh -c.  
> • Emit warnings and require interactive confirmation for command-based resolution.
> 
> * * *
> 
> ### 2) Self-upgrade downloads unsigned binaries
> 
> Evidence: internal/update/upgrade.go
> 
> downloadFile(ctx, downloadURL, archivePath)  
> …  
> if err := extractBinaryTo(archivePath, tempFile); err != nil { … }
> 
> Risk: The update flow downloads a tarball over HTTPS but does not verify signature or  
> checksum. If GitHub release artifacts are tampered with or a MITM/local proxy is present, an  
> attacker can replace the binary.
> 
> Mitigations:
> 
> • Publish and verify checksums or signatures (e.g., SHA256 + signature or sigstore).  
> • Pin TLS with checksum verification for assets.  
> • Consider prompting user and showing checksum for manual verification.
> 
> * * *
> 
> ## Medium Severity Findings
> 
> ### 3) Shell tool relies on approvals but lacks robust non‑TTY hardening
> 
> Evidence: internal/tools/shell.go, internal/tools/config.go
> 
> cmd := exec.CommandContext(execCtx, shell, “-c”, a.Command)
> 
> The approval system relies on:
> 
> • ShellAllow patterns  
> • ShellAutoRun + env variables  
> • Interactive prompt
> 
> But shell tool can run in non‑TTY contexts if ShellNonTTYEnv is set. If that env var is set  
> in automation, it becomes a headless RCE surface via model output.
> 
> Risk: If any tool call can be coerced or untrusted input is routed to shell, it becomes a  
> powerful execution channel.
> 
> Mitigations:
> 
> • In non‑TTY mode, require explicit --shell-allow allowlist and disable ad‑hoc approvals.  
> • Require per-command approval even with ShellAutoRun unless a strict allowlist match is  
> present.  
> • Log and persist shell tool usage with the command for auditability.
> 
> * * *
> 
> ### 4) SSRF potential via URL tools/providers
> 
> Evidence: internal/llm/read\_url\_tool.go, provider code (OpenAI/Claude/xAI/etc.)
> 
> jinaURL := “[https://r.jina.ai/](https://r.jina.ai/)” + url  
> req, err := http.NewRequestWithContext(ctx, “GET”, jinaURL, nil)
> 
> Multiple places accept arbitrary URLs or user-provided endpoints. Some are raw HTTP client  
> requests with no allowlist or blocked internal IP ranges.
> 
> Risk: If LLM prompts or user inputs feed URLs, the tool can request arbitrary destinations.  
> This can be used for SSRF (internal network access), metadata access (cloud instance  
> metadata), or targeted scanning.
> 
> Mitigations:
> 
> • Validate URLs and block internal/reserved IP ranges.  
> • Allowlist protocols (https only) and optionally domains.  
> • Add optional “safe mode” to disable arbitrary URL fetches.
> 
> * * *
> 
> ## Low Severity / Hardening Opportunities
> 
> ### 5) WriteFileTool temp file pattern could be abused via symlink races
> 
> Evidence: internal/tools/write.go
> 
> tempFile := absPath + “.tmp”  
> os.WriteFile(tempFile, …)  
> os.Rename(tempFile, absPath)
> 
> Risk: If an attacker controls the target directory, they can create symlinks or replace .tmp  
> to target an arbitrary file. This is a classic TOCTOU issue when using predictable temp  
> filenames.
> 
> Mitigations:
> 
> • Use os.CreateTemp in the same directory and os.Rename to avoid predictable temp names.  
> • Use O\_EXCL style creation if possible.
> 
> * * *
> 
> ### 6) ReadFileTool accepts arbitrary path once approved
> 
> Evidence: internal/tools/read.go, approval.go
> 
> The approval model grants directory-level access. Once a directory is approved, any file in  
> it can be read. This is expected but becomes sensitive if directory approvals are too broad  
> (e.g., home directory).
> 
> Mitigations:
> 
> • Provide clearer warnings about approving large directory scopes.  
> • Optionally support file-level approvals in addition to directory approvals.
> 
> * * *
> 
> ## Notable Good Practices
> 
> • Tool allowlists and approval flow: ToolPermissions and ApprovalManager are good guardrails.  
> • Path canonicalization and symlink handling: avoids common path traversal issues.  
> • Output truncation: prevents tool output flooding.
> 
> * * *
> 
> ## Recommendations (Prioritized)
> 
> 1. Remove or strictly gate $(…) command execution in config.
> 2. Implement upgrade binary verification (hash/signature).
> 3. Harden shell tool for non‑TTY usage with strict allowlists only.
> 4. Add URL validation and SSRF protection in read\_url\_tool and any open URL fetches.
> 5. Harden write tool temp-file handling with CreateTemp.
> 
> * * *
> 
> If you want, I can provide a patch plan or concrete code changes for any of the above.

(the first item is actually on purpose to support 1password, and it is a sharp tool after all, but I will certainly ponder about this)
