Security
August 12, 2026 · View on GitHub
omg.dev is powerful on purpose, and that means it has a real blast radius. Please understand it before you run it anywhere shared.
What omg.dev can do
- Spawns AI coding agents with shell access. Sessions run
claude/codex/agenton your box (often with permissions skipped so they don't block), so an agent can read, write, and execute within the repos it's launched into. - Exposes an unauthenticated HTTP API on
LFG_PORT(default8766). Anyone who can reach that port can list sessions, start new agents, send them input, and answer their prompts. There is no login — this is by design, on the assumption the port is reachable only over a private network. - Reads local files and logs. Collectors read git history and repo files; the
optional
security_scancollector runs read-only host probes (login history, listening ports, cron/systemd, SSH authorized_keys, package audits). - Talks to services you configure — GitHub, OpenRouter, an optional voice speech-to-text upstream, and optionally WhatsApp.
How to run it safely
- Never bind to a public interface. Keep
LFG_HOST=127.0.0.1. The provided systemd unit hard-sets this so a stale.envcan't override it. - Keep repro servers loopback-only. For throwaway static servers, use
python3 -m http.server --bind 127.0.0.1 <port>and stop the process when done. Never leave a/tmpor worktree repro server listening on0.0.0.0. - Reach it over Tailscale, not the internet. Use
tailscale serve(HTTPS on your MagicDNS name, tailnet members only). Do not usetailscale funnel, and do not open8766/443in your cloud firewall.scripts/setup.shsets this up for you. - Run as a non-root user. The setup script refuses to run as root and installs a systemd user service. Agents should never run as root.
- Scope your credentials. Use a dedicated, least-privilege GitHub token and SSH keys; assume anything reachable by an agent on the box is reachable by omg.dev.
- Treat Tailscale auth keys as secrets. Pass
TS_AUTHKEYon the setup command line only; it is never written to disk. Prefer ephemeral, pre-approved, tagged, single-use keys.
Dependency auditing
bun.lock is the only lockfile that describes what we ship — the Dockerfile
copies it, CI runs bun install --frozen-lockfile, and the service runs under
bun. GitHub Dependabot cannot parse bun.lock; it only understands
package-lock.json / yarn.lock / pnpm-lock.yaml. Stale npm lockfiles used
to sit in the repo, so Dependabot spent its time on a dependency graph nobody
installed while missing the real one. Those files are gone — do not reintroduce
one to appease a scanner.
Use bun audit instead. The audit workflow runs it on every push and PR plus
weekly (so advisories published against an unchanged graph still surface), and
fails on new high/critical findings.
Two things to know before changing dependencies:
overridesinpackage.jsonexist for security patching. Most advisories here land on transitive packages, so the fix is to pin the patched version rather than add a direct dependency. Keep every override inside the range its consumers already accept — a same-major bump. Do not runbun update <pkg>on a transitive package: it promotes it to a direct dependency at the newest major, which can hand a consumer a version it never agreed to.- Accepted exceptions live in the workflow, not in someone's memory. If an
advisory has no fixed release, add a
--ignore=<GHSA-id>with a comment covering why the exposure is acceptable and what removes it. The workflow always prints the unfiltered report to the job summary so an exception cannot silently become permanent.
Reporting a vulnerability
Please open a private security advisory on the GitHub repository (or email the maintainer) rather than filing a public issue. We'll respond as quickly as we can.