
Asymmetric defense against adversarial AI agents. VeilGate evaluates each incoming request, redirects suspected agents into a per-IP-consistent honeypot environment, and quantifies the computational cost imposed on the attacker.
VeilGate is an open-source deception proxy for teams that want to raise the cost of automated security probing without putting fragile block rules in front of real users.
It sits in front of a web application, scores each request, and chooses one of three outcomes:
The goal is not magic invulnerability. The goal is better economics: keep humans and normal automation moving, while making AI-assisted scanners spend time, tokens, and attention on believable dead ends.
observe, challenge, tarpit, and threshold-driven auto modes.X-Veilgate-Token
header transports so cross-origin SPAs can solve and reattach the token
on subsequent API calls. The 401 challenge response is SPA-aware: it returns
HTML for top-level navigations and JSON (with the PoW metadata to solve
inline) for fetch / XHR contexts.Downloads the binary, installs a systemd service, installs community rules, and
writes a starter config in observe mode.
# One-liner
curl -sSL https://veilgate.dev/install.sh | sudo bash -s -- --upstream http://localhost:3000
# Or download first, then run
curl -sSL https://veilgate.dev/install.sh -o install.sh
sudo ./install.sh --upstream http://localhost:3000
Flags:
The packaged config uses rules_dir: "~/.veilgate/rules". Under systemd,
VeilGate runs as the veilgate user whose home is /var/lib/veilgate, so this
resolves to /var/lib/veilgate/.veilgate/rules.
If --secret is omitted on a new install, the installer prompts on interactive
terminals and otherwise generates a random secret. If the service user does not
exist, the installer asks before creating it on interactive terminals and
defaults to creation for non-interactive installs.
After install:
systemctl status veilgate
journalctl -u veilgate -f
docker run -d --name veilgate \
--network host \
-v /etc/veilgate/veilgate.yaml:/etc/veilgate/veilgate.yaml:ro \
-v ~/.veilgate/rules:/home/nonroot/.veilgate/rules \
-e VEILGATE_SECRET=$(openssl rand -hex 32) \
ghcr.io/c0oki3s/veilgate:latest -config /etc/veilgate/veilgate.yaml
Prerequisite: Go 1.25.10 or newer.
git clone https://github.com/C0oki3s/veilgate.git
cd veilgate
make build
./veilgate -config configs/veilgate.yaml
By default VeilGate listens on :8080, proxies to http://localhost:3000,
and exposes metrics on :9090.
The default config starts in observe mode — baseline normal traffic before
enabling challenge or tarpit.
Recommended rollout:
observe for at least several days.challenge for ambiguous traffic.tarpit once your thresholds match your environment.Start with configs/veilgate.yaml:
listen: ":8080"
upstream: "http://localhost:3000"
mode: "observe"
rules_dir: "~/.veilgate/rules"
detector:
score_challenge_threshold: 40
score_tarpit_threshold: 70
trusted_ips: []
trusted_proxies: []
metrics:
listen: ":9090"
Full reference: Configuration reference.
VeilGate ships no embedded rules. The binary reads rules_dir at startup
and hot-reloads changes; if the directory is empty it starts with zero detection
signals. Rules come from one place:
install.sh script clones it
automatically on first install. You can also update it manually with the
built-in update-rules subcommand — no rebuild, no restart:| Installs rules automatically? | |
|---|---|
install.sh (first run) | Yes — clones via git |
# Install the latest pack into ~/.veilgate/rules (the default location)
veilgate update-rules
# Or pin to a release tag
veilgate update-rules --dir ~/.veilgate/rules --version v1.2.0
# List available releases
veilgate update-rules --list
After the install, VeilGate's fsnotify watcher picks up the new files
within ~500 ms. Each existing file is backed up as <name>.bak before
being overwritten (pass --no-backup to skip). The installed version is
recorded in <rules_dir>/.rules-version.json so CI and operators can
check what is running without consulting git metadata.
Treat both directories as security policy — review changes before
deploying to production, especially detector.yaml and ip_reputation.yaml.
Full guide and rollback procedure:
docs/how-to/install-community-rules.md.
veilgate.yaml and rule files.veilgate update-rules.VEILGATE_SECRET or challenge.secret before using challenge or
tarpit mode. VeilGate refuses to start outside observe mode with the
default challenge secret.rules/ as security policy. Review and version them.make test
make fmt
make build
The top-level tests folder contains black-box integration tests. Package-private unit tests live next to their packages because they verify unexported detector, TLS fingerprint, tarpit, and ML helpers.
Apache-2.0. See LICENSE.
| Flag | Default | Description |
|---|
--upstream URL | http://127.0.0.1:3000 | Your upstream application |
--listen ADDR | :8080 | Proxy listen address |
--metrics-listen ADDR | 127.0.0.1:9090 | Metrics (keep private) |
--secret SECRET | prompt or generated | Challenge signing secret |
--user USER | veilgate | Service user to run VeilGate |
--no-service | — | Skip systemd service |
--no-rules | — | Skip community rules install |
| Mode | Use it when | Behavior |
|---|
observe | Initial rollout and tuning | Scores and records traffic, always forwards upstream |
challenge | You are comfortable interrupting suspicious clients | Medium-score traffic gets proof of work |
tarpit | You are ready to deceive high-confidence agents | High-score traffic receives the fake app |
auto | You want thresholds to drive enforcement per request | Forward below threshold, challenge middle scores, tarpit high scores |
veilgate binary (startup) | No — reads rules_dir, never fetches |
veilgate update-rules | Only when you explicitly call it |