Overview
This guide shows how to route selected traffic through Riscosity (e.g., the Governance Proxy / AI Firewall) without changing enterprise DNS. Instead, we apply per-endpoint overrides by updating the hosts file using CrowdStrike Real Time Response (RTR). You can do this with either runscript (preferred for repeatable automation) or runshell (ad-hoc command execution).
Riscosity still provides visibility and governance over those flows once traffic lands on the proxy.
When to use this approach
- Pilot rollouts or canary groups where DNS changes are undesirable.
- Segmented or offline systems where central DNS cannot be updated quickly.
- Temporary enforcement/redirect for investigation or containment.
Objective
For a target domain (e.g., api.vendor-ai.com), direct traffic to a Riscosity proxy IP (e.g., 10.0.5.20) at the endpoint layer.
Hosts file entry (example):
10.0.5.20 api.vendor-ai.com- The endpoint resolves api.vendor-ai.com to the Riscosity IP; the proxy then forwards to the actual vendor, applying Riscosity policy (visibility, redaction, blocking, etc.).
Considerations
- Hosts files are per-endpoint and override DNS for exact hostnames only (no wildcards).
- Many AI vendors use multiple hostnames and CDNs—enumerate all required FQDNs you want governed via Riscosity.
- If the application uses IPv6, add IPv6 mappings or force IPv4 for testing.
- Maintain a rollback plan (the scripts below auto-create backups).
Prerequisites
- CrowdStrike Falcon with RTR access and sufficient permissions (write/execute).
- Riscosity proxy reachable IP from the endpoints.
- Exact hostnames you want to override (start with a canary set, then expand).
- Maintenance window if required by change control.
Two Ways to Execute in RTR
Option A — runscript (recommended)
- Executes a Cloud File (uploaded script) or a script you put into the session.
- Best for repeatability, auditability, and scale.
Cloud File usage
# Linux/macOS endpoint
runscript -CloudFile=update-hosts.sh -CommandLine="--add '10.0.5.20 api.vendor-ai.com'"# Windows endpoint
runscript -CloudFile=Update-Hosts.ps1 -CommandLine="-Add '10.0.5.20 api.vendor-ai.com'"Using a script you uploaded in-session
put update-hosts.sh
runscript -ScriptName=update-hosts.sh -CommandLine="--add '10.0.5.20 api.vendor-ai.com'"put Update-Hosts.ps1
runscript -ScriptName=Update-Hosts.ps1 -CommandLine="-Add '10.0.5.20 api.vendor-ai.com'"Option B — runshell (ad-hoc / fallback)
# Windows (PowerShell)
put .\Update-Hosts.ps1
runshell PowerShell.exe -ExecutionPolicy Bypass -File .\Update-Hosts.ps1 -Add "10.0.5.20 api.vendor-ai.com"# Linux/macOS (bash)
put update-hosts.sh
runshell chmod +x ./update-hosts.sh && ./update-hosts.sh --add "10.0.5.20 api.vendor-ai.com"Use either runscript or runshell. If runshell is unavailable in your tenant/policy, use runscript.
Quoting & Syntax “Gotchas” (Read This First)
These are the most common reasons runscript throws “unknown argument” or fails to pass parameters:
- Use equals with no quotes on -CloudFile and -ScriptName.
- ✅ -CloudFile=Update-Hosts.ps1
- ❌ -CloudFile "Update-Hosts.ps1" or -CloudFile='Update-Hosts.ps1'
- Wrap the entire -CommandLine in straight ASCII double quotes (").
- Inside that string, you may use single quotes around your script’s argument payload.
- Example (Linux/macOS):
-CommandLine="--add '10.0.5.20 api.vendor-ai.com'" - Example (Windows/PowerShell):
-CommandLine="-Add '10.0.5.20 api.vendor-ai.com'"
- Avoid curly “smart quotes”. Copy/paste from docs or chat can introduce “ ” or ‘ ’. Replace them with plain " " and ' '.
- Case & name must match Cloud File exactly, including extension (.ps1/.sh).
- If you have no arguments, omit -CommandLine entirely.
- Windows vs Linux quoting rules differ. If you see parsing errors, try:
- Windows: -CommandLine="-Add \"10.0.5.20 api.vendor-ai.com\""
- Linux/macOS: -CommandLine="--add '10.0.5.20 api.vendor-ai.com'"
- Don’t use sudo in the script when invoked via RTR; RTR runs with sufficient rights.
Validation & Rollback
Validation
Windows:
Get-Content C:\Windows\System32\drivers\etc\hosts | Select-String api.vendor-ai.com
Test-NetConnection api.vendor-ai.com -Port 443Linux/macOS:
getent hosts api.vendor-ai.com || (command -v dscacheutil >/dev/null && dscacheutil -q host -a name api.vendor-ai.com)
curl -v https://api.vendor-ai.com/ -m 5Flush resolver cache (only if you don’t immediately see new resolution):
- Windows: ipconfig /flushdns
- macOS: sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
- Linux (systemd): sudo resolvectl flush-caches
Rollback
- Both scripts create a timestamped backup (.bak).
- Restore by copying the backup over the hosts file:
- Windows: Copy-Item hosts.YYYYMMDD-HHMMSS.bak hosts -Force
- Linux/macOS: install -m 0644 /etc/hosts.YYYYMMDD-HHMMSS.bak /etc/hosts
Production Tips
- Start with a canary group, then expand.
- Log the change (who, when, what) and keep backups until verified.
- Map all required hostnames that your app actually uses (monitor with Riscosity to discover AI vendor endpoints).
- IPv6: If apps prefer IPv6, also add IPv6 entries or force IPv4 during testing.
- Security tooling: Hosts overrides can bypass DNS-based controls. Keep scope tight and documented.
- Idempotent runs: Re-running the add operation just updates the mapping; remove reverts the single hostname.
Scripts (Drop-in Ready)
A) Windows PowerShell — Update-Hosts.ps1
<#
.SYNOPSIS
Safely add/update/remove entries in the Windows hosts file.
.PARAMETER Add
Add or update an entry. Format: "IP Hostname" (e.g., "10.0.5.20 api.vendor-ai.com").
.PARAMETER Remove
Remove an entry by hostname (e.g., "api.vendor-ai.com").
.PARAMETER List
Show current, non-comment hosts entries.
.PARAMETER Path
Optional path to hosts file. Default: C:\Windows\System32\drivers\etc\hosts
.EXAMPLES
.\Update-Hosts.ps1 -Add "10.0.5.20 api.vendor-ai.com"
.\Update-Hosts.ps1 -Remove "api.vendor-ai.com"
.\Update-Hosts.ps1 -List
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$false)]
[string]$Add,
[Parameter(Mandatory=$false)]
[string]$Remove,
[Parameter(Mandatory=$false)]
[switch]$List,
[Parameter(Mandatory=$false)]
[string]$Path = "C:\Windows\System32\drivers\etc\hosts"
)
function Fail($msg) { Write-Error $msg; exit 1 }
if (-not (Test-Path -LiteralPath $Path)) { Fail "Hosts file not found at: $Path" }
if ($Add -and $Remove) { Fail "Use either -Add or -Remove, not both." }
if (-not $Add -and -not $Remove -and -not $List) { Fail "Specify -Add, -Remove, or -List." }
$original = Get-Content -LiteralPath $Path -Raw
$lines = $original -split "`r?`n"
$timestamp = (Get-Date).ToString("yyyyMMdd-HHmmss")
$backupPath = "$Path.$timestamp.bak"
Copy-Item -LiteralPath $Path -Destination $backupPath -Force | Out-Null
function Normalize-Hostname($h) { return $h.Trim().ToLower() }
function Is-Comment($l) { return $l.TrimStart().StartsWith("#") -or $l.Trim() -eq "" }
if ($List) {
$entries = $lines | Where-Object { -not (Is-Comment $_) } | ForEach-Object { $_.Trim() }
$entries | ForEach-Object { Write-Output $_ }
Write-Output "`nBackup saved: $backupPath"
exit 0
}
if ($Add) {
$parts = $Add -split "\s+"
if ($parts.Count -ne 2) { Fail "Use -Add ""<IP> <Hostname>"" (e.g., -Add ""10.0.5.20 api.vendor-ai.com"")." }
$ip = $parts[0].Trim()
$host = Normalize-Hostname $parts[1]
$ipv4 = '^(?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d)$'
$ipv6 = '^(?:[A-Fa-f0-9]{1,4}:){1,7}[A-Fa-f0-9]{0,4}$'
if (-not ($ip -match $ipv4 -or $ip -match $ipv6)) { Fail "Invalid IP: $ip" }
$filtered = @()
foreach ($l in $lines) {
if (Is-Comment $l) { $filtered += $l; continue }
$tokens = ($l -split "\s+") | Where-Object { $_ -ne "" }
if ($tokens.Count -ge 2) {
$existingHost = Normalize-Hostname $tokens[1]
if ($existingHost -eq $host) { continue }
}
$filtered += $l
}
$newLine = "$ip`t$host"
$filtered += $newLine
($filtered -join "`r`n") + "`r`n" | Set-Content -LiteralPath $Path -Encoding Ascii -Force
Write-Output "Set mapping: $host -> $ip"
Write-Output "Backup saved: $backupPath"
exit 0
}
if ($Remove) {
$host = Normalize-Hostname $Remove
$filtered = @()
$removed = $false
foreach ($l in $lines) {
if (Is-Comment $l) { $filtered += $l; continue }
$tokens = ($l -split "\s+") | Where-Object { $_ -ne "" }
if ($tokens.Count -ge 2) {
$existingHost = Normalize-Hostname $tokens[1]
if ($existingHost -eq $host) { $removed = $true; continue }
}
$filtered += $l
}
if (-not $removed) { Write-Output "No entry found for hostname: $host" }
($filtered -join "`r`n") + "`r`n" | Set-Content -LiteralPath $Path -Encoding Ascii -Force
Write-Output "Removed mapping for: $host"
Write-Output "Backup saved: $backupPath"
exit 0
}
B) Linux/macOS bash — update-hosts.sh
#!/usr/bin/env bash
# Safely add/update/remove entries in /etc/hosts (or a custom path)
# Usage:
# ./update-hosts.sh --add "10.0.5.20 api.vendor-ai.com"
# ./update-hosts.sh --remove "api.vendor-ai.com"
# ./update-hosts.sh --list
# ./update-hosts.sh --path "/custom/hosts" --add "10.0.5.20 api.vendor-ai.com"
set -euo pipefail
PATH_ARG="/etc/hosts"
MODE=""
ARG=""
while [[ $# -gt 0 ]]; do
case "$1" in
--add) MODE="add"; ARG="$2"; shift 2;;
--remove) MODE="remove"; ARG="$2"; shift 2;;
--list) MODE="list"; shift;;
--path) PATH_ARG="$2"; shift 2;;
*) echo "Unknown arg: $1"; exit 1;;
esac
done
if [[ -z "${MODE}" ]]; then
echo "Specify one of --add, --remove, or --list"; exit 1
fi
if [[ ! -f "$PATH_ARG" ]]; then
echo "Hosts file not found at: $PATH_ARG" >&2; exit 1
fi
timestamp="$(date +%Y%m%d-%H%M%S)"
backup="${PATH_ARG}.${timestamp}.bak"
cp -f "$PATH_ARG" "$backup"
trim() { awk '{$1=$1};1'; }
if [[ "$MODE" == "list" ]]; then
awk '!/^[[:space:]]*#/ && NF >= 2 {print}' "$PATH_ARG"
echo
echo "Backup saved: $backup"
exit 0
fi
if [[ "$MODE" == "add" ]]; then
read -r ip host <<<"$(echo "$ARG" | trim)"
if [[ -z "${ip:-}" || -z "${host:-}" ]]; then
echo 'Use --add "IP Hostname" (e.g., --add "10.0.5.20 api.vendor-ai.com")' >&2; exit 1
fi
ipv4='^((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$'
ipv6='^([A-Fa-f0-9]{1,4}:){1,7}[A-Fa-f0-9]{0,4}$'
if ! [[ "$ip" =~ $ipv4 || "$ip" =~ $ipv6 ]]; then
echo "Invalid IP: $ip" >&2; exit 1
fi
tmp="$(mktemp)"
awk -v h="$host" '
BEGIN{IGNORECASE=1}
/^[[:space:]]*#/ {print; next}
{
keep=1
if (NF >= 2) {
if (tolower($2) == tolower(h)) { keep=0 }
}
if (keep) print
}' "$PATH_ARG" > "$tmp"
printf "%s\t%s\n" "$ip" "$host" >> "$tmp"
echo "" >> "$tmp"
install -m 0644 "$tmp" "$PATH_ARG"
rm -f "$tmp"
echo "Set mapping: $host -> $ip"
echo "Backup saved: $backup"
exit 0
fi
if [[ "$MODE" == "remove" ]]; then
host="$(echo "$ARG" | trim)"
tmp="$(mktemp)"
awk -v h="$host" '
BEGIN{IGNORECASE=1}
/^[[:space:]]*#/ {print; next}
{
if (NF >= 2 && tolower($2) == tolower(h)) { next }
print
}' "$PATH_ARG" > "$tmp"
if ! grep -qiE "^[[:space:]]*[^#].*[[:space:]]${host}([[:space:]]|$)" "$PATH_ARG"; then
echo "No entry found for hostname: $host"
fi
echo "" >> "$tmp"
install -m 0644 "$tmp" "$PATH_ARG"
rm -f "$tmp"
echo "Removed mapping for: $host"
echo "Backup saved: $backup"
exit 0
fi
End-to-End Examples
Add / update mapping
# Linux/macOS
runscript -CloudFile=update-hosts.sh -CommandLine="--add '10.0.5.20 api.vendor-ai.com'"# Windows
runscript -CloudFile=Update-Hosts.ps1 -CommandLine="-Add '10.0.5.20 api.vendor-ai.com'"Remove mapping
# Linux/macOS
runscript -CloudFile=update-hosts.sh -CommandLine="--remove 'api.vendor-ai.com'"# Windows
runscript -CloudFile=Update-Hosts.ps1 -CommandLine="-Remove 'api.vendor-ai.com'"List current (non-comment) entries
# Linux/macOS
runscript -CloudFile=update-hosts.sh -CommandLine="--list"# Windows
runscript -CloudFile=Update-Hosts.ps1 -CommandLine="-List"