WAI Docs Wed Aug 19 13:22:37 EDT 2026
List
Quick Start
Quick Start
User Guide
User Guide
Policies - GuardRails
Policies - GuardRails
Witness Anywhere: Remote Device Security
Witness Anywhere: Remote Device Security
Witness Attack
Witness Attack
Administrator Guide
Administrator Guide
404
404
Configuring Claude Proxy via Witness Anywhere
Note: New and updated features may not be immediately available on your dedicated deployment due to participation in limited release availability, beta programs, or regional configurations.
If you don't see a feature you expect, please reach out to your Customer Success team — we're happy to help.
Overview
By default, the Claude application and Claude CLI does not honor system-wide proxy settings, opting instead for direct outbound traffic. Consequently, WitnessAI is unable to intercept prompt and response traffic from devices integrated via Witness Anywhere. To ensure proper traffic routing through the WitnessAI proxy, administrators must define the proxy settings in the settings file of Claude application.
Solutions for macOS and Windows
The following sections outline the recommended procedures for applying these configurations across macOS and Windows environments.
macOS Configuration
WitnessAI has integrated logic within the Witness Anywhere registration script to automatically insert the required proxy configuration into the Claude application's settings file. This ensures that only Claude-specific traffic is routed via the WitnessAI proxy, leaving other system traffic unaffected.
New Witness Anywhere Deployments
For new deployments, download the latest registration script from the WitnessAI console and distribute it via your Mobile Device Management (MDM) solution.
Note: Claude must be installed on the target device prior to deploying Witness Anywhere to ensure the script can successfully modify the environment file.
Existing Deployments
For previously registered devices, administrators should deploy the following shell script via MDM to append the proxy environment variable to the Claude configuration.
#!/bin/bash # Run as root: set Claude Code HTTP_PROXY for the logged-in console user. set -euo pipefail PROXY_URL='http://127.0.0.1:9411' log() { printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >&2; } die() { log "ERROR: $*"; exit 1; } remove_json_comments() { local text="${1-}" out="" i=0 len c next local in_str=false esc=false line=false block=false len=${#text} while (( i < len )); do c="${text:i:1}" if $line; then [[ "$c" == $'\n' ]] && { line=false; out+="$c"; } ((i++)); continue fi if $block; then next="${text:i+1:1}" [[ "$c" == '*' && "$next" == '/' ]] && { block=false; ((i += 2)); continue; } ((i++)); continue fi if $in_str; then out+="$c" if $esc; then esc=false elif [[ "$c" == '\\' ]]; then esc=true elif [[ "$c" == '"' ]]; then in_str=false; fi ((i++)); continue fi if [[ "$c" == '"' ]]; then in_str=true; out+="$c"; ((i++)); continue; fi next="${text:i+1:1}" [[ "$c" == '/' && "$next" == '/' ]] && { line=true; ((i += 2)); continue; } [[ "$c" == '/' && "$next" == '*' ]] && { block=true; ((i += 2)); continue; } out+="$c"; ((i++)) done printf '%s' "$out" } remove_json_trailing_commas() { local text="${1-}" out="" i=0 len c j next local in_str=false esc=false len=${#text} while (( i < len )); do c="${text:i:1}" if $in_str; then out+="$c" if $esc; then esc=false elif [[ "$c" == '\\' ]]; then esc=true elif [[ "$c" == '"' ]]; then in_str=false; fi ((i++)); continue fi if [[ "$c" == '"' ]]; then in_str=true; out+="$c"; ((i++)); continue; fi if [[ "$c" == ',' ]]; then j=$((i + 1)) while (( j < len )) && [[ "${text:j:1}" =~ [[:space:]] ]]; do ((j++)); done if (( j < len )); then next="${text:j:1}" [[ "$next" == '}' || "$next" == ']' ]] && { ((i++)); continue; } fi fi out+="$c"; ((i++)) done printf '%s' "$out" } [[ "${EUID:-$(id -u)}" -eq 0 ]] || die "Must run as root." user="$(stat -f '%Su' /dev/console 2>/dev/null || true)" [[ -n "$user" && "$user" != "root" && -d "/Users/$user" ]] || die "No logged-in user found." settings_file="/Users/$user/.claude/settings.json" bkp_file="${settings_file}.bkp" as_user() { sudo -u "$user" "$@"; } if ! as_user test -f "$settings_file"; then log "INFO: Claude Code config not present ($settings_file), nothing to do." exit 0 fi raw="$(as_user cat "$settings_file" 2>/dev/null)" || die "Failed to read $settings_file." [[ -n "${raw//[$'\t\r\n ']/}" ]] || raw='{}' json_text="$(remove_json_trailing_commas "$(remove_json_comments "$raw")")" updated="$(printf '%s' "$json_text" | python3 -c ' import json, sys raw = sys.stdin.read() try: data = json.loads(raw) if raw.strip() else {} except json.JSONDecodeError: sys.exit(1) if not isinstance(data, dict): sys.exit(1) env = data.get("env") if not isinstance(env, dict): env = {} data["env"] = env env["HTTP_PROXY"] = "'"$PROXY_URL"'" print(json.dumps(data, indent=2)) ' 2>/dev/null)" || die "Failed to update Claude Code proxy settings." as_user rm -f "$bkp_file" 2>/dev/null || true as_user mv "$settings_file" "$bkp_file" || die "Failed to back up $settings_file." printf '%s\n' "$updated" | as_user tee "$settings_file" >/dev/null || die "Failed to write $settings_file." log "SUCCESS: Claude Code HTTP proxy set for '$user' ($settings_file)"
Windows Configuration
WitnessAI has integrated logic within the Witness Anywhere registration script to automatically insert the required proxy configuration into the Claude application's settings file. This ensures that only Claude-specific traffic is routed via the WitnessAI proxy, leaving other system traffic unaffected.
New Witness Anywhere Deployments
For new deployments, download the latest registration script from the WitnessAI console and distribute it via your Mobile Device Management (MDM) solution.
Note: Claude must be installed on the target device prior to deploying Witness Anywhere to ensure the script can successfully modify the environment file.
Existing Deployments
For previously registered devices, administrators should deploy the following shell script via MDM to append the proxy environment variable to the Claude configuration.
# Run elevated: set Claude Code HTTP_PROXY for the logged-in console user. #Requires -Version 5.1 Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $ProxyUrl = 'http://127.0.0.1:9411' function Write-Log { param([string]$Message) $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' Write-Host "[$timestamp] $Message" } function Write-LogError { param([string]$Message) Write-Log "ERROR: $Message" exit 1 } function Get-LoggedInUsername { $loggedInUser = (Get-WmiObject -Class Win32_ComputerSystem -ErrorAction Stop).UserName if ([string]::IsNullOrWhiteSpace($loggedInUser)) { Write-LogError 'No user is currently logged in.' } if ($loggedInUser -match '\\') { return ($loggedInUser -split '\\', 2)[1] } return $loggedInUser } # Strips // and /* */ comments for JSON parse (strings preserved; comments not kept on write) function Remove-JsonComments { param([string]$Text) $sb = [System.Text.StringBuilder]::new() $inStr = $false; $esc = $false; $line = $false; $block = $false for ($i = 0; $i -lt $Text.Length; $i++) { $c = $Text[$i] if ($line) { if ($c -eq "`n") { $line = $false; [void]$sb.Append($c) }; continue } if ($block) { if ($c -eq '*' -and $Text[$i+1] -eq '/') { $block = $false; $i++ }; continue } if ($inStr) { [void]$sb.Append($c) if ($esc) { $esc = $false } elseif ($c -eq '\') { $esc = $true } elseif ($c -eq '"') { $inStr = $false } } elseif ($c -eq '"') { $inStr = $true; [void]$sb.Append($c) } elseif ($c -eq '/' -and $Text[$i+1] -eq '/') { $line = $true; $i++ } elseif ($c -eq '/' -and $Text[$i+1] -eq '*') { $block = $true; $i++ } else { [void]$sb.Append($c) } } return $sb.ToString() } # Removes trailing commas before } or ] (strings preserved) function Remove-JsonTrailingCommas { param([string]$Text) $sb = [System.Text.StringBuilder]::new() $inStr = $false; $esc = $false for ($i = 0; $i -lt $Text.Length; $i++) { $c = $Text[$i] if ($inStr) { [void]$sb.Append($c) if ($esc) { $esc = $false } elseif ($c -eq '\') { $esc = $true } elseif ($c -eq '"') { $inStr = $false } continue } if ($c -eq '"') { $inStr = $true; [void]$sb.Append($c); continue } if ($c -eq ',') { $j = $i + 1 while ($j -lt $Text.Length -and [char]::IsWhiteSpace($Text[$j])) { $j++ } if ($j -lt $Text.Length -and ($Text[$j] -eq '}' -or $Text[$j] -eq ']')) { continue } } [void]$sb.Append($c) } return $sb.ToString() } function Set-ClaudeCodeHttpProxy { param([string]$Username) $settingsFile = Join-Path "$env:SystemDrive\Users\$Username\.claude" 'settings.json' if (-not (Test-Path $settingsFile)) { Write-Log "INFO: Claude Code config not present ($settingsFile), nothing to do." exit 0 } try { $raw = Get-Content -Path $settingsFile -Raw -ErrorAction Stop if ([string]::IsNullOrWhiteSpace($raw)) { $raw = '{}' } $jsonText = Remove-JsonTrailingCommas (Remove-JsonComments $raw) if ($PSVersionTable.PSVersion.Major -ge 6) { $json = $jsonText | ConvertFrom-Json -Depth 10 } else { $json = $jsonText | ConvertFrom-Json } if ($null -eq $json.env -or $json.env -isnot [PSCustomObject]) { $json | Add-Member -NotePropertyName env -NotePropertyValue ([PSCustomObject]@{}) -Force } $json.env | Add-Member -NotePropertyName HTTP_PROXY -NotePropertyValue $ProxyUrl -Force $bkpFile = "$settingsFile.bkp" if (Test-Path $bkpFile) { Remove-Item -Path $bkpFile -Force } Move-Item -Path $settingsFile -Destination $bkpFile -Force $json | ConvertTo-Json -Depth 10 | Set-Content -Path $settingsFile -Encoding UTF8 Write-Log "SUCCESS: Claude Code HTTP proxy set for '$Username' ($settingsFile)" } catch { Write-LogError "Failed to configure Claude Code HTTP proxy for '$Username': $_" } } $principal = New-Object Security.Principal.WindowsPrincipal( [Security.Principal.WindowsIdentity]::GetCurrent() ) if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-LogError 'Must run as Administrator.' } $username = Get-LoggedInUsername $userProfile = Join-Path "$env:SystemDrive\Users" $username if (-not (Test-Path $userProfile)) { Write-LogError "No profile directory found for logged-in user '$username'." } Set-ClaudeCodeHttpProxy -Username $username
Following the application of the environment variable, restart the Claude application for changes to take effect.