npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

bugxhunter

v0.9.5

Published

BugXHunter: an AI security-testing agent with a sandboxed runner, a passkey-sealed key vault and read-only GitHub access. `npx bugxhunter` runs it on your machine.

Readme

BugXHunter

CI CodeQL Built with Claude Code Reviewed by Claude Mythos 5.1

The BugXHunter security-testing agent runner: a web UI for the OpenCode coding agent, running on open-weight models (GLM-5.3 by default) through SCX.ai. The UI follows bugxhunter.com's design system — a macOS-style terminal window, the red-team palette (GitHub-dark surfaces with red, amber, cyan and green accents) and Fira Code throughout. Started from the sovgov-poc chatbot designer.

  • Runner — point it at a project folder and drive OpenCode's build (edits + shell) or plan (read-only) agent. Every file edit and shell command waits for your approval. Markdown replies, collapsible tool calls and reasoning, per-turn token counts, and a Changes view of what the agent edited (git repos only — OpenCode tracks changes via git).
  • Playground — chat with any SCX, Anthropic (Claude), NVIDIA or OpenRouter model directly (no agent), with tool-calling, JSON mode, an embeddings-backed knowledge base and browser voice. Also:
    • Security presets (code review, threat modelling, AI system review, pentest planning, diagram review, diagram drawing, tabletop exercises, CTF coaching, phishing, log triage, vulnerability explaining) and compare mode (2–3 models side by side, with speed and tokens). Every preset, the canvas and the agent work from one catalogue (web/src/intel): OWASP Top 10:2025, API Security Top 10:2023, Top 10 for LLM Applications 2025, Top 10 for Agentic Applications 2026, Mobile Top 10 2024, ASVS 5.0, WSTG 4.2, STRIDE, and MITRE ATLAS tactics, techniques and mitigations for attacks on AI systems, so findings cite the same ids everywhere.
    • Flag highlighting for CTFs and labs: anything matching the flag format (a regular expression in the sidebar, default flag{...} and the like) is marked in replies and tool output, in both modes.
    • Images for vision models, and draw.io files (.drawio, compressed or not, and .drawio.svg) for any model: the file becomes an exact text outline of its zones, boxes, legend colours and arrows, so labels are never misread.
    • Diagrams in replies: a model writes a ```drawio spec and the app draws it as an editable .drawio.svg (drawgen), checks it, and can send the problems back for a fix.
    • Threat-model canvas: build a model from a diagram or description, track findings, scope and coverage, zoom and pan, export JSON, findings.md, SVG or draw.io.
    • Saved sessions: chats and canvases are sealed with the vault key on the runner (Docker: the runner-data volume), never in browser storage.
    • Retired NVIDIA models (their endpoints answer 404) are found and hidden automatically.

Screenshots

The agent working in a project — live tool calls, reasoning, and a markdown summary:

BugXHunter — the agent reading a project and summarising it

Point it at any folder; resume past sessions; approve edits and commands as they happen. The key vault's state and lock live in the sidebar footer:

BugXHunter — Runner landing view

Playground — compare SCX models directly with full generation controls:

BugXHunter — Playground

Install

The quickest way, with Node 22+ installed, is the npm package (OpenCode comes with it):

npx bugxhunter            # runs the agent on this machine; UI opens at http://localhost:8790
npx bugxhunter docker     # the sandboxed stack instead (needs Docker Desktop): pulls the signed
                          # images for this version into ~/.config/bugxhunter/docker and starts them

npm i -g bugxhunter makes it a plain bugxhunter command; bugxhunter --help lists the options (--port, --dir, --no-open; docker --slim|--full, docker down|logs|ps, docker export <path> [dest]; vault reset). The current folder becomes the default project. Then, in the sidebar: set up the vault with a passkey, add your SCX.ai key as SCX_API, and connect GitHub. The package is published by the release workflow with npm provenance: npm audit signatures confirms it was built from this repository.

Requirements (from source)

  • Node 22+
  • OpenCode on PATH: npm install here provides it, or npm i -g opencode-ai
  • An SCX.ai key: in the vault (preferred), else opencode auth login (choose Other, provider id scx) or SCX_API in a .env here.

Run from source

npm install
npm run dev          # backend :8790 + web :5190, with hot reload
npm start            # or: the compiled app, the same way `npx bugxhunter` runs it (npm run build first)

Open http://localhost:5190 (dev) or http://localhost:8790 (npm start).

The backend starts its own OpenCode server on 127.0.0.1:8791 (it stops a stale one left on that port by a previous run). Everything listens on localhost only. There are no passwords: until you set up the vault the app is open, and from then on you sign in with the vault's passkey.

Docker (sandboxed agent + login)

npx bugxhunter docker does all of this (any OS). By hand, from a checkout:

powershell -File docker/setup.ps1     # once: writes .env — the secrets the two containers share
docker compose up -d --build          # build locally, or `docker compose pull && docker compose up -d`
                                      # for the published images (set BXH_VERSION in .env to pin a signed release)

The images are multi-arch (linux/amd64 and linux/arm64, so Apple Silicon and Graviton run them natively) with zstd-compressed layers (Docker 23+). The agent image comes in two flavours: the default carries the scan toolchain (nuclei, nmap, httpx, katana, ffuf, gitleaks, testssl and wordlists) plus the Rust and Go toolchains, about 750 MB to download; -slim leaves all of that out for code review only, about a third of the size (npx bugxhunter docker --slim, or BXH_AGENT_FLAVOR=-slim in .env). Open http://localhost:8790 and set up the vault in the sidebar: it seals your SCX key and turns on passkey sign-in. (setup.ps1 -CopyScxKey copies the key into .env instead, in the clear.)

Three containers (plus the egress logger):

| Container | Holds | Network | |---|---|---| | runner | Web UI, login, SCX key, /scx/v1 key proxy | shared bridge, published on 127.0.0.1 | | agent | OpenCode, the agent's shell + scan tools, /workspace volume | shared bridge — direct internet | | render | drawgen: model-written diagram specs → .drawio.svg, and .drawio files → outlines | internal network shared only with runner — no internet |

  • Model output and uploaded diagram files are parsed in render, not in the runner that holds the keys: no volumes, no secrets, read-only, non-root, 512 MB and 1 CPU, each job in its own process with a 10 s limit. drawgen is installed from a release wheel pinned by SHA-256.

  • The agent's model calls go to runner's proxy with a proxy token; the proxy swaps in the real key and only allows /chat/completions and /models. The SCX key never enters the agent container — this holds even though the agent has direct internet.

  • Projects live in the workspace Docker volume (/workspace, a git repo so Changes work). No host folders are mounted.

  • Workspaces and files in the UI: the sidebar's workspaces button lists the folders under /workspace (locally ~/bugxhunter/repos, or OPEN_RUNNER_WORKSPACE), including GitHub clones, and creates a new one (an empty git repository) or deletes one. A delete asks for the name typed back, the open project can't be deleted, and only a listed workspace can be. The files button browses the open project: click a file to download it, and upload with the button or by dropping files on the list (up to 200 MB each). An upload never replaces a file; a clash is saved as name-1.ext.

  • From the command line, copy a repo in as a snapshot, and results back out:

    powershell -File docker/copy-in.ps1 C:\code\my-repo          # -> /workspace/my-repo (skips node_modules, .env, …)
    powershell -File docker/copy-out.ps1 my-repo C:\temp\my-repo-out

    (Plain docker compose cp also copies in, but leaves files owned by root, so neither the agent nor uploads can write there. To fix a folder copied that way: docker run --rm -u root -v bugxhunter_workspace:/workspace --entrypoint chown ghcr.io/cintelis/bugxhunter-agent -R node:node /workspace/<folder>.)

  • Getting files out: /workspace is a Docker volume, so there is no host folder to open. Any file path the agent prints under the project (for example "Saved as /workspace/acme/app/analysis.md") is a download link in the UI, served only for files inside the project folder. From a terminal, npx bugxhunter@latest docker export acme/app/analysis.md (or an absolute /workspace/... path; optional destination as the second argument) copies a file or folder out.

  • The agent has direct internet so scan tools run at full speed (nmap/ping/raw DNS work via NET_RAW). Outbound connections are logged, not restricted — only point the agent at targets you are authorised to test, and run this on a trusted machine/VM.

  • Both containers run as non-root with no-new-privileges; the agent drops all capabilities except NET_RAW and is limited to 2 CPUs, 4 GB RAM, 512 processes. Shell commands and file edits are approved in the UI — that, plus the container/VM boundary and the isolated SCX key, is what contains the agent.

  • Logs (the audit log of prompts, tool calls and approvals, plus the egress log of hosts the agent connected to) live in the logs volume, which the agent container can't see. Read them with docker compose cp runner:/logs ./logs.

  • Port 8790 is published on localhost only. Put TLS (a reverse proxy) in front and set COOKIE_SECURE=1, TRUST_PROXY=1 and ALLOWED_HOSTS=<your domain> before exposing it to anyone else.

Key vault

The SCX key (and any other secret the agent needs) lives in a vault that is sealed at rest: on disk there is only ciphertext and wrapped keys, so a copied .env, volume or container yields nothing. Set it up from the sidebar after the first start; it takes a minute:

  1. Passkey — Windows Hello, Touch ID, Android, or a security key. One touch unlocks the vault and signs you in; the authenticator's own biometric or PIN is the second factor. It derives a secret (WebAuthn PRF) that never leaves the device. Chrome, Edge and Safari 18+; Firefox can't do this yet. Open the app as http://localhost:…, not by IP.
  2. Recovery code — shown once, stored nowhere. Keep it offline. It opens the vault if the passkey is lost.
  3. Backup passphrase (optional) — a way in on a device without the passkey.

The decryption key lives only in the backend's memory, so after every restart, and after 2 hours without activity (OPEN_RUNNER_VAULT_IDLE_MINUTES), someone has to unlock it before the agent can call a model. Ctrl+Shift+L locks it at once. The crypto is symmetric only (AES-256-GCM, HKDF-SHA-256, PBKDF2-SHA-256), which keeps it out of reach of a quantum attacker; see SECURITY.md.

While the vault is locked, model calls fail with a clear "vault is sealed" message. Without a vault the app takes the key from a key file (SCX_API_FILE), else falls back to SCX_API in .env or OpenCode's auth.json, in the clear. A key file is for a runner nobody unlocks, such as one behind Sigilant: mount it as a secret; it is re-read on every call, so replacing it rotates the key, and if it cannot be read the call fails rather than falling back to a key in the clear.

Sign-in is the same passkey. Once a vault exists the API needs a session, and the ways in are a WebAuthn assertion with one of the vault's passkeys (verified server-side), the backup passphrase, or the recovery code. One touch at the sign-in screen signs in and unlocks the vault. Keep two passkeys on different devices (keys dialog → add passkey). Lost every factor? Someone with access to the server's files runs npm run vault:reset (Docker: docker compose exec runner rm /data/vault.json): the vault and its secrets are gone and the app reopens for a fresh setup. Nothing on the network can do that, which is what keeps the lock meaningful.

Other models via OpenRouter

SCX.ai is the default provider. To use anything from OpenRouter's catalogue as well:

  1. Add your OpenRouter key to the vault as OPENROUTER_API_KEY (keys dialog in the sidebar). The Playground then lists OpenRouter's models under their own heading, addressed as openrouter/<id>.
  2. For the agent, list the ids it may use in OPENROUTER_MODELS (comma-separated, e.g. anthropic/claude-sonnet-4.5,openai/gpt-6.1-sol), in .env. Only those appear in the Runner's model picker, as openrouter/…. In Docker, both containers read the same variable.

The agent never holds the key: its calls go to the runner's /openrouter/v1 proxy with the proxy token, exactly like SCX, in both local and Docker modes. Pricing is OpenRouter's; the Playground shows each model's per-token rates.

Claude via the Anthropic API

  1. Add your Anthropic key to the vault as ANTHROPIC_API_KEY (keys dialog). The Playground then lists every Claude model the key can use under an Anthropic heading, addressed as anthropic/<id> (for example anthropic/claude-opus-5-5).
  2. The agent gets Claude Opus 5.5, Sonnet 5.5 and Haiku 5.5 in the Runner's model picker. Locally, ANTHROPIC_MODELS (comma-separated model ids) changes that list; in Docker the list is in docker/opencode.json.

As with the other providers, the agent never holds the key: OpenCode's own Anthropic client calls the runner's /anthropic/v1 proxy with the proxy token, and the runner adds the key.

Things that differ from the OpenAI-style providers:

  • Sampling settings are not sent. Current Claude models reject temperature and top-p, so the Playground's sliders don't apply to them. Forced tool use is sent as "auto" for the same reason.
  • Safety classifiers. Claude's classifiers can decline some security requests. On models that support it, the Playground asks for Anthropic's server-side fallback, so a declined request is retried on the model Anthropic recommends for that category. A decline that still stands shows as an error naming the category. For authorised security work, Anthropic's Cyber Verification Program can lift cyber-category declines.
  • Prompt caching is on, so repeated history in a long chat is billed at the cached rate.

GitHub repositories (read-only)

To review a repository, clone it into the workspace from the sidebar (clone from GitHub under the project folder). The first time, click Connect GitHub: a short code appears, you enter it at github.com/login/device, and the runner is signed in. Then Choose repositories on GitHub opens the app's install screen, where you pick which repositories it may read; the list in the dialog refreshes when you come back. Nothing to register, no token to paste.

The sign-in is to the public BugXHunter GitHub App, which declares only Contents: read-only and Metadata: read-only, so even GitHub will refuse a push with its token. It reaches only the repositories you install it on, and you can change that list or revoke the app on GitHub at any time. Its tokens expire after eight hours and are refreshed by the runner; the pair is sealed in the vault (or, before a vault exists, kept in memory until the runner restarts).

A clone lands in <workspace>/<owner>/<repo> (Docker: the shared workspace volume; locally ~/bugxhunter/repos, or OPEN_RUNNER_WORKSPACE) and becomes the project folder. Cloning again fast-forwards it and never resets local edits.

The runner does the cloning, the agent gets a working copy. The token is passed to git as a process-scoped header, so it is in neither the command line nor the clone's .git/config. The agent can read, grep and scan the code (gitleaks over the history included) and edit it locally, but nothing in the sandbox can fetch, push, open issues or see any other repository. Pushing results back is deliberately not built: findings leave through the UI, not through your GitHub account.

A fork that wants its own app registers one (device flow on, Contents: read-only, installable on any account) and sets GITHUB_CLIENT_ID and GITHUB_APP_SLUG.

Security-testing tools (authorised use only)

The agent image ships a standard pentest toolchain for authorised testing (your own sites, labs, CTFs). Build with --build-arg SECTOOLS=0 to leave them out.

  • Vuln / web: nuclei (templates baked in offline), httpx, katana (SPA/JS crawler), ffuf (+ SecLists wordlists in /opt/wordlists), testssl, curl, openssl, subfinder (passive).
  • Secrets (local, no network): gitleaks — scan copied-in repos and JS bundles for leaked keys.
  • CTF and forensics (full image): file, binutils, binwalk, exiftool, exiv2, pngcheck, steghide, foremost, 7z, tshark, john, sqlmap, gdb, strace (ltrace on amd64), and Python's pwntools, pycryptodome, z3 and yara, for labs and CTFs the user owns or is registered for. --build-arg CTFTOOLS=0 leaves them out; CTFTOOLS=1 adds them to a slim build. gef, RsaCtfTool, Volatility 3, radare2 and rockyou install on demand into /workspace/.tools (recipes in docker/agent-AGENTS.md), and the agent's instructions carry a first-look playbook per category.
  • Rust and Go: cargo (with clippy, rustfmt and cargo audit for RustSec advisories) and go (with govulncheck), to build, test and audit Rust and Go repositories. --build-arg RUST=0 or GO=0 leaves one out; RUST=1 / GO=1 adds it to a slim build.
  • Raw-socket: nmap, ping, traceroute, dig/host (incl. zone transfer).
  • Not included — LLM red-teaming: promptfoo (~1.4 GB installed) and garak (~2 GB with CPU-only PyTorch, 5 GB+ if pip is left to pull the CUDA build) would more than double the image, so the agent installs them on demand into the persistent /workspace/.tools volume. The recipe, including pointing them at the runner's model proxy for grading, is in docker/agent-AGENTS.md.

All tools run directly against targets. The agent's AGENTS.md tells it to confirm authorisation before scanning and to scan only hosts you name.

Making scans fast (they're slow if done naively):

  • Scope nuclei templates — the biggest lever. -tags cve,exposure or -severity critical,high,medium instead of all ~14k templates. Fingerprint with httpx first and target the detected stack.
  • Pre-filter with katana/httpx and feed only live URLs into nuclei/ffuf.
  • Tune to the target: -c 50 -rl 300 -bulk-size 50 -timeout 5 on a tolerant host; lower on a CDN/WAF target, where aggression trips rate-limits and is slower.
  • Run long scans detached, writing to /workspace (-o result.txt), and poll the file so an aborted turn doesn't lose progress.

To fence the agent to a specific lab/target range, add firewall rules on the Docker host or the VM you run this in — Docker's bridge NAT doesn't restrict outbound on its own.

Through Sigilant (governed runs)

The runner can run under Sigilant, Cintelis's agent governance platform: it is a registered agent there, every call it makes is decided by a gateway against the scope the customer signed, risky ones wait for a person, and each is written to a signed audit chain. Sigilant's side of that (the runner's tools behind the gateway, the MCP bridge its agent calls through, the GitHub App, the webhooks and the scheduler) lives in Sigilant's repository, which is private. This repository needs nothing for it beyond what it already has: the runner's API, the agent's OPENCODE_CONFIG merge, and SCX_API_FILE for a runner nobody is there to unlock.

Configuration (environment variables)

| Variable | Default | Purpose | |---|---|---| | OPEN_RUNNER_MODEL | scx/GLM-5.3 | Default model for both agents | | OPEN_RUNNER_DIR | this folder | Default project folder | | OPEN_RUNNER_AGENT_PORT | 8791 | Port for the OpenCode server | | PORT | 8790 | Backend port | | SCX_API_FILE | unset | A file holding the SCX key, re-read on every call; for a runner with no one to unlock the vault. Ignored once a vault exists | | SCX_API | the vault, else opencode auth login | SCX key in the clear; ignored once a vault or key file exists (prefer either) | | OPENROUTER_API_KEY_FILE | unset | A file holding the OpenRouter key, as SCX_API_FILE | | OPENROUTER_API_KEY | the vault, else unset | OpenRouter key in the clear; prefer the vault item of the same name | | OPENROUTER_MODELS | unset | Comma list of OpenRouter model ids the agent may use; becomes an OpenCode provider through the proxy | | OPENROUTER_BASE_URL | https://openrouter.ai/api/v1 | OpenRouter endpoint | | ANTHROPIC_API_KEY_FILE | unset | A file holding the Anthropic key, as SCX_API_FILE | | ANTHROPIC_API_KEY | the vault, else unset | Anthropic key in the clear; prefer the vault item of the same name | | ANTHROPIC_MODELS | claude-opus-5-5,claude-sonnet-5-5,claude-haiku-5-5 | Claude model ids in the agent's picker (local mode; Docker: docker/opencode.json) | | ANTHROPIC_BASE_URL | https://api.anthropic.com/v1 | Anthropic endpoint | | GITHUB_CLIENT_ID | the BugXHunter app | A fork's own GitHub App (device flow); GITHUB_APP_SLUG names its install page | | OPEN_RUNNER_VAULT_FILE | ~/.config/bugxhunter/vault.json | The sealed vault (Docker: /data/vault.json on the runner-data volume) | | OPEN_RUNNER_VAULT_IDLE_MINUTES | 120 | Auto-lock after this long without a model call or API write; 0 = never | | OPEN_RUNNER_SECRET | random per start | Signs session cookies; set it to keep sign-ins across restarts | | COOKIE_SECURE | unset | 1 marks the session cookie Secure (behind TLS) | | TRUST_PROXY | unset | Behind a reverse proxy: 1 (hop count), loopback, or a CIDR list — so the cookie's Secure flag and client IPs are right | | OPEN_RUNNER_LOG_DIR | unset (off) | Folder for the JSONL audit log (Docker sets /logs) | | ALLOWED_HOSTS | localhost only | Extra Host header values to accept (comma list), e.g. the domain a reverse proxy serves. Everything else gets 403, which blocks DNS-rebinding attacks | | OPEN_RUNNER_ALLOWED_ROOTS | any folder | Local mode: folders the UI may open, PATH-style list (; on Windows, : elsewhere). Set it before sharing the app | | OPENCODE_URL | unset (spawn locally) | Use a remote OpenCode server (Docker sets http://agent:4096) | | OPEN_RUNNER_RENDER_URL | unset (diagrams off) | The render service for diagrams and .drawio files (Docker sets http://render:8080) | | OPEN_RUNNER_PLAYGROUND_DIR | playground/ beside the vault | Saved Playground chats and canvases, sealed with the vault key | | OPEN_RUNNER_WORKSPACE | /workspace (local: ~/bugxhunter/repos) | Remote mode: projects must live under this folder. Both modes: where GitHub clones land | | SCX_PROXY_TOKEN | unset | Enables the /scx/v1 key proxy for the sandboxed agent |

Releases are on the releases page. See SECURITY.md to verify one by hand, or to report a vulnerability.

Releases

Every published release, newest first. Each is signed with the Cintelis release key; scripts/verify-release.sh refuses anything that isn't. A release ships an app archive (the compiled server and web app, runnable with Node and no Docker), a deploy archive (docker-compose.yml and the setup scripts, pinned to that version's images), images.txt (both GHCR images by digest) and the signed checksums.txt that covers them all.

| Release | Published | Checksums | Signature | Signature check | Build | | --- | --- | --- | --- | --- | --- | | v0.9.4 | 2026-10-29 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.9.3 | 2026-10-29 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.9.2 | 2026-10-28 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.9.1 | 2026-10-28 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.9.0 | 2026-10-28 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.8.7 | 2026-10-28 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.8.6 | 2026-10-27 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.8.5 | 2026-10-21 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.8.4 | 2026-10-21 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.8.3 | 2026-10-21 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.8.2 | 2026-10-21 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.8.1 | 2026-10-09 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.8.0 | 2026-10-09 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.7.0 | 2026-10-08 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.6.0 | 2026-10-08 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.5.0 | 2026-10-07 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.4.0 | 2026-10-07 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.3.0 | 2026-10-07 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.2.0 | 2026-10-07 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run | | v0.1.0 | 2026-10-07 | checksums.txt | checksums.txt.sig | ✅ release key | workflow run |

Signature check: checksums.txt.sig verified against the release key (SHA256:RY9yd61LBZCa5WrzSkEet+1Dnt2zVu9zpMRbZMWIV+I) when this table was generated by scripts/release-table.sh. To check a download yourself, see SECURITY.md.

To use a release, verify it first (scripts/verify-release.sh vX.Y.Z, see SECURITY.md), then either unpack the deploy archive and run docker compose pull && docker compose up -d (its VERSION file pins the images), or unpack the app archive and run npm ci --omit=dev && NODE_ENV=production node server/dist/index.js.

Development

npm run check        # typecheck + lint + unit tests (what CI runs)
npm run typecheck    # tsc, both workspaces
npm run lint         # eslint (typescript-eslint + react-hooks), warnings fail
npm test             # vitest: the pure logic in server/src and web/src
npm run build        # web -> web/dist, server -> server/dist (what the Docker image ships)

GitHub Actions: ci.yml runs the checks (including the render service's Python tests) and builds the Docker images on every push and PR, codeql.yml scans for security issues weekly and on PRs, docker-publish.yml pushes the images to GHCR (ghcr.io/cintelis/bugxhunter-runner, bugxhunter-agent and bugxhunter-render) on master and on v* tags, and Dependabot keeps npm, Actions and base images current.

Server and browser share one type contract in shared/ (agent.d.ts, scx.d.ts): the server's event mapping must produce those shapes and the client consumes them, so a change on either side fails the other's type-check.

Releasing

Bump version in package.json, then tag and push; the release workflow checks, builds the archives and the versioned images with provenance attestations, and creates a draft. Then sign it with the offline release key, which verifies the draft's attestations and checksums first and publishes it:

git tag -a v1.0.0 -m "BugXHunter v1.0.0"
git push origin v1.0.0
# once the workflow finishes (10-15 minutes, the agent image is large):
scripts/sign-release.sh v1.0.0

On Windows, run the signing script from PowerShell through Git Bash: & 'C:\Program Files\Git\bin\bash.exe' scripts/sign-release.sh v1.0.0. It asks for the key's passphrase once. Only admins can push v* tags.

After publishing, the script regenerates the release table above (scripts/release-table.sh) and opens a pull request for it that merges itself once CI passes.

Publishing the release (the signing script's last step) also publishes the npm package: the workflow's npm job runs on the release published event, so npm never carries an unsigned release (npm run pack:npm assembles it from the same build, with provenance). That needs the package's trusted publisher on npmjs.com set to this repository and release.yml, once; no npm token is stored.

Layout

| Path | Role | |---|---| | server/src/opencode.ts | Starts/stops the OpenCode server, one SDK client per project folder, event mapping | | server/src/index.ts | Express: /api/agent/* (OpenCode) and /api/chat, /api/models, /api/kb (SCX) | | server/src/scx.ts, rag.ts | SCX client and in-memory knowledge base (Playground) | | server/src/providers.ts, anthropic.ts, nvidia-health.ts | Anthropic / NVIDIA / OpenRouter providers (Claude via the official SDK); hides NVIDIA models whose endpoints are retired | | server/src/playground-store.ts | Saved Playground sessions, sealed with the vault key | | server/src/render.ts, docker/render-server.py, docker/drawio_outline.py | The render service (diagrams, .drawio outlines) and the runner's client for it | | web/src/Canvas.tsx, web/src/canvas/ | The threat-model canvas | | web/src/intel/, web/src/presets.ts, docker/agent-AGENTS.md | The security catalogue (OWASP, ASVS, WSTG, STRIDE, MITRE ATLAS) as data, the prompts built from it, and the agent's methodology, which a test keeps in step with the catalogue | | web/src/DrawioBlock.tsx, diagrams.ts | Diagrams in replies | | shared/ | Type contract between server and browser | | scripts/ | sign-release.sh (maintainer, offline key), verify-release.sh (users), release-table.sh, the release public key | | web/src/AgentPanel.tsx | Runner transcript, approvals and session flow; DiffModal.tsx and QuestionCard.tsx hold the Changes view and agent questions | | web/src/Sidebar.tsx | Project folder picker (Runner) and model/prompt settings (Playground) | | web/src/styles.css, brand.tsx, Terminal.tsx | bugxhunter.com theme tokens, the >_ BugXHunter wordmark, terminal title bar and typed boot sequence |

AI assistance

BugXHunter was built with Claude Code, and the codebase was reviewed and hardened by Claude Mythos 5.1 (bug fixes, the security hardening, tests and CI). The app shows this with Anthropic's Claude wordmark, used as published. It is a model credit, not an endorsement by Anthropic; the maintainers are responsible for the code.

License

MIT © Cintelis.

BugXHunter ships a security-testing toolchain for authorised testing only (your own systems, labs, CTFs). You are responsible for how you use it.