NullWire-MCP

io.github.VoxNode-ux由 GitHub 帳號 VoxNode-ux 發布v1.0.2更新於 Oct 29, 2026

RAM-only HTTP debugging proxy and MCP server in Go. AI agents see salted tags, never secrets.

發布方自己的服務:Wire Cash: bank wire fees and transfer costs

已驗證STDIO僅桌面開發者工具安全與監控

概覽

AI 產生的概覽

在本機執行、只存在記憶體中的 HTTP/HTTPS/WebSocket 除錯代理,透過 MCP 把已去識別化的流量副本交給 AI 助理查看。

可以做什麼
  • 依數量、方法或 URL 篩選檢視最近擷取的請求與回應流,敏感值已換成帶鹽標籤
  • 把某筆擷取的請求重建為已去識別化的 curl 指令,被遮蔽的值改為需自行填寫的環境變數
  • 清空記憶體中最多 50 筆流的環狀緩衝並重設計數
  • 透過正向代理、HTTPS 通道、反向閘道或 WebSocket 文字訊框擷取流量
  • 掃描本機 MCP 設定、.env、TOML、YAML 與 ZIP 檔案中的密鑰,並把伺服器註冊到支援的 MCP 用戶端
適用情境
適合讓助理排查失敗的 API 呼叫、401 錯誤或 WebSocket 問題,而不必把 Authorization 標頭、Cookie、連線字串或客戶資料貼進對話。也適合要求流量不出本機、不寫入磁碟的本機除錯情境。
執行需求
以 stdio 方式作為本機程序執行;可用單一靜態 Go 二進位檔,或透過 npx、Homebrew、Scoop、Docker 及發行檔安裝。未宣告需要帳號、API 金鑰或環境變數。需把應用程式指向本機代理(HTTP_PROXY、HTTPS_PROXY 或 base URL)才能擷取流量。
安裝前請注意
去識別化依賴樣式與啟發式規則,形狀罕見或隨機性低的密鑰可能漏掉並送達模型,建議為已知密鑰補上自訂規則。install 指令會修改 MCP 用戶端設定檔(會先備份),scan 會讀取本機設定、.env 與歷史紀錄檔。發行版二進位檔沒有作業系統程式碼簽章,執行前應驗證校驗碼與建置來源。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 NullWire-MCP,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

⚡ NullWire-MCP

See the traffic. Never the secrets.

A zero-dependency, RAM-only network inspector that lets your AI assistant debug HTTP, HTTPS and WebSocket traffic, with every secret scrubbed before the model ever sees it.

[CI and Release] [Security checks] [Go 1.26] [Dependencies: none] [Disk writes: 0] [MCP]

Quick start · How it works · What gets redacted · MCP tools · Configuration · CLI reference · Security model


🧠 Why NullWire exists

Your AI assistant is great at debugging an API call, until the request it needs to read carries an Authorization header, a session cookie, a database URL or a customer's email. Pasting raw traffic into a chat means pasting your secrets with it.

NullWire sits between your app and the network. It records what passes through, scrubs every secret out of the recorded copy, and hands that clean copy to your assistant through the Model Context Protocol. Your app keeps working exactly as before, because the live traffic is never touched.

text
  your app ──► NullWire (127.0.0.1) ──► the real server                    │                    ├─ forwards every byte, unmodified                    └─ keeps a scrubbed copy in RAM ──► your AI assistant (MCP)

✨ At a glance

🪶 Zero dependenciesGo standard library only. One static binary, nothing to install.
🧠 RAM onlyThe last 50 flows live in memory. The server never writes a file, and a stop signal wipes the buffer. (install edits your MCP client configs, but only when you run it.)
🔒 Loopback onlyThe proxy binds to 127.0.0.1. A DNS-rebinding guard answers only loopback Host headers.
🧽 Layered redactionPrivate keys, JSON/XML/query secrets, JWTs, 50+ vendor key formats, IPs, secrets hiding in base64, and a randomness detector for keys nobody has seen before.
🛡️ Fail-closed shieldsBodies that can't be inspected are refused or flagged, never silently passed to the model.
🔌 HTTP, HTTPS and WebSocketPlain proxying, blind CONNECT tunnels, a reverse gateway for full HTTPS visibility, and WebSocket text capture in both directions.
🔁 Safe replayExport any captured request as a curl command with secrets swapped for environment variables.
🔎 Secret scannerscan and protect look for secrets in your MCP configs, .env, TOML, YAML and ZIP files before they leak.
📱 Runs anywhereLinux, macOS, Windows, Docker and Termux on Android.

🚀 Quick start

1. Install it

Pick whichever fits your machine. Every method checks the download against the release's SHA256SUMS.txt and installs nothing if it doesn't match. Release binaries also carry signed GitHub build provenance, and each release includes a CycloneDX SBOM (nullwire-sbom.cdx.json).

With Node.js (no install step): npx
bash
npx -y nullwire-mcp install --client all

Nothing to download by hand: the launcher fetches and verifies the binary on first run and keeps it in a cache folder. Your MCP clients are then set to run npx -y nullwire-mcp.

macOS, Linux and Termux: install script
bash
curl -fsSL https://raw.githubusercontent.com/VoxNode-ux/nullwire-mcp/main/scripts/install.sh | sh -s -- --setup

Installs to ~/.local/bin (or $PREFIX/bin on Termux). --setup also registers NullWire with your MCP clients. Drop it to install only. --uninstall removes everything again.

Windows: install script
powershell
irm https://raw.githubusercontent.com/VoxNode-ux/nullwire-mcp/main/scripts/install.ps1 | iexnullwire-mcp install --client all

Installs to %LOCALAPPDATA%\Programs\nullwire-mcp and adds it to your user PATH. To pass options, run it as & ([scriptblock]::Create((irm https://raw.githubusercontent.com/VoxNode-ux/nullwire-mcp/main/scripts/install.ps1))) -Setup.

Homebrew and Scoop
bash
brew install VoxNode-ux/nullwire/nullwire-mcp                                   # macOS, Linuxscoop bucket add nullwire https://github.com/VoxNode-ux/scoop-nullwire           # Windowsscoop install nullwire-mcp

Both packages are generated from the templates in packaging/.

Download a release by hand
PlatformFile
Linux x86-64 / ARM64 (Raspberry Pi 4+, Termux)nullwire-linux-amd64 / nullwire-linux-arm64
Linux ARMv7 (older Raspberry Pi) / RISC-V 64nullwire-linux-armv7 / nullwire-linux-riscv64
macOS Intel / Apple Siliconnullwire-darwin-amd64 / nullwire-darwin-arm64
Windows x86-64 / ARM64nullwire-windows-amd64.exe / nullwire-windows-arm64.exe
FreeBSD x86-64nullwire-freebsd-amd64
bash
chmod +x nullwire-linux-amd64sha256sum -c SHA256SUMS.txt --ignore-missing   # verify the download (macOS: shasum -a 256 -c)gh attestation verify nullwire-linux-amd64 --repo VoxNode-ux/nullwire-mcp   # optional: verify signed build provenance
Build from source
bash
go install github.com/VoxNode-ux/nullwire-mcp@latest# orgit clone https://github.com/VoxNode-ux/nullwire-mcp && cd nullwire-mcpCGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o nullwire-mcp .

Go 1.26 or newer. There is nothing to go get: the module has no dependencies.

Docker
bash
docker run -i --rm ghcr.io/voxnode-ux/nullwire-mcp

The server speaks MCP over stdio, so run it with -i. The proxy listens on the container's own loopback by design, so a published port (-p) cannot reach it. On Linux, add --network host to use it from the host's 127.0.0.1.

2. Add it to your MCP clients

One command registers NullWire with every supported client it finds on your machine:

bash
nullwire-mcp install --client all --dry-run   # look first: nothing is writtennullwire-mcp install --client all             # then do it, and restart the client

It covers Claude Desktop, Claude Code, Cursor, Windsurf, VS Code, Cline, Roo Code, Gemini CLI and Codex CLI. See Connect your MCP clients for details, or add it by hand:

bash
# Claude Codeclaude mcp add nullwire -- /path/to/nullwire-mcp
jsonc
// Claude Desktop, Cursor, Windsurf, Cline and other JSON-configured clients{  "mcpServers": {    "nullwire": {      "command": "/path/to/nullwire-mcp",      "args": ["-port", "8080"]    }  }}

The client starts NullWire, and NullWire starts the proxy in the same process. A live status bar on stderr shows what is happening:

text
⚡ [NullWire-MCP] Proxy 127.0.0.1:8080 | RAM Ring: 3/50 | Scrubbed: 7 Tokens, 2 Cookies, 1 IPs | Disk: 0B

3. Send some traffic through it

bash
# Plain HTTP through the proxycurl -x http://127.0.0.1:8080 http://httpbin.org/headers
# HTTPS through the proxy (a blind tunnel, see "How it works")curl -x http://127.0.0.1:8080 https://example.com
# HTTPS with full request visibility: the reverse gatewaynullwire-mcp -target https://api.example.comcurl http://127.0.0.1:8080/v1/things -H "Authorization: Bearer sk-live-..."

4. Ask your assistant

"Use inspect_traffic to show my last 5 requests and tell me why the third one returned 401."


🔭 How it works

mermaid
flowchart LR    A[Your app or curl] -->|HTTP_PROXY / base URL| P[NullWire proxy<br/>127.0.0.1:8080]    P -->|unmodified bytes| S[(Real server)]    S -->|unmodified bytes| P    P --> C[Capture copy]    C --> R[Redaction layers]    R --> B[(RAM ring<br/>50 flows)]    B -->|MCP over stdio| M[AI assistant]

The key idea: the model reads a scrubbed copy, your app talks to the real server. Nothing the proxy forwards is rewritten, so debugging never changes the behaviour you are debugging.

Four ways to capture traffic

ModeHow you use itWhat the assistant sees
Forward proxyHTTP_PROXY=http://127.0.0.1:8080 and http:// URLsFull request and response, scrubbed
HTTPS tunnelHTTPS_PROXY=http://127.0.0.1:8080 (CONNECT)Only the target host:port, timing and byte counts. The encrypted payload is never opened.
Reverse gatewayPoint your app's base URL at http://127.0.0.1:8080 and start with -target https://… (or send an X-Target-URL header)Full HTTPS request and response, scrubbed. NullWire makes the TLS connection to the real server.
WebSocketAny Upgrade: websocket request through either proxy modeText messages in both directions, scrubbed, as one flow recorded when the connection closes. Frames are forwarded unmodified.

Why no HTTPS interception? Reading HTTPS from a forward proxy would require a custom root certificate installed on your machine. That is key material and a trust-store change, the opposite of a zero-footprint tool. The reverse gateway gets you the same visibility with no certificate games.

Several APIs at once

Give each upstream a name. The first path segment picks the upstream and is removed before forwarding:

bash
nullwire-mcp -target openai=https://api.openai.com,anthropic=https://api.anthropic.com
export OPENAI_BASE_URL=http://127.0.0.1:8080/openai/v1       # → https://api.openai.com/v1export ANTHROPIC_BASE_URL=http://127.0.0.1:8080/anthropic    # → https://api.anthropic.com

Names are letters, digits, ., _ and - (up to 32 characters, case-insensitive). One unnamed URL may be added as the default for paths that match no name. An X-Target-URL header overrides everything for a single request.


🧰 MCP tools

NullWire exposes three tools over stdio. It speaks MCP protocol versions 2026-07-28, 2025-11-25 and 2024-11-05, and accepts JSON-RPC batches.

ToolWhat it doesArguments
inspect_trafficReturns recent scrubbed flows.limit (1 to 50, default 10), method, url_filter
export_sanitized_curlRebuilds a captured request as a curl command. Redacted values become environment variables you fill in yourself.flow_id (required)
clear_ram_bufferWipes all 50 slots and resets the counters.none

A flow looks like this (illustrative):

json
{  "id": 7,  "timestamp": "2026-10-31T09:14:02Z",  "method": "POST",  "url": "https://api.example.com/v1/charge",  "request_headers": { "Authorization": "[REDACTED_TOKEN#a1b2c3]", "Content-Type": "application/json" },  "request_body": "{\"card_token\":\"[REDACTED_TOKEN#9f3e21]\",\"amount\":4200}",  "status_code": 401,  "response_body": "{\"error\":\"invalid_api_key\"}",  "latency_ms": 143,  "redaction_count": 2}

Tags are stable and correlatable. [REDACTED_TOKEN#a1b2c3] is a short salted hash, so the same secret gets the same tag everywhere in one run. Your assistant can see that two requests used the same token without learning it. The salt is random per run, so tags can't be compared across restarts or reversed.

Tag kinds: TOKEN, COOKIE, IP and KEY (private keys).

export_sanitized_curl produces something like:

bash
# Replay of flow 7# Set environment variables first:# export NULLWIRE_AUTH_TOKEN=...   # was [REDACTED_TOKEN#a1b2c3]curl -X POST 'https://api.example.com/v1/charge' \  -H "Authorization: $NULLWIRE_AUTH_TOKEN" \  -H 'Content-Type: application/json' \  --data-raw '…'

Placeholders are NULLWIRE_AUTH_TOKEN, NULLWIRE_COOKIE, NULLWIRE_IP and NULLWIRE_PRIVATE_KEY. CONNECT tunnels have no replayable request, and NullWire says so.


🧽 What gets redacted

Every URL, header, request body and response body passes through these layers, in this order:

#LayerCatchesExample
1Private keysPEM blocks: RSA, EC, OpenSSH, encrypted, PGP; JSON-escaped ones; blocks cut off by a size limit-----BEGIN PRIVATE KEY-----…
2Secret fieldsJSON string values and arrays, and query parameters, for names like password, api_key, access_token, secret, session_id"password": ["a","b"], ?api_key=…
3XML elementsElement text for secret-looking names, with namespaces and CDATA; the tags themselves stay intact<wsse:Password>…</wsse:Password>
4URL credentialsuser:password@host in any URL or connection stringpostgres://app:pw@db/prod
5Auth schemesBearer, Basic and Token credentialsAuthorization: Bearer …
6JWTsThree-part eyJ… tokens
7Vendor keys50+ formats in three tiers (below)AKIA…, ghp_…, sk-ant-…, SG.…
8Secret-named fieldskey: value or key=value pairs where the name says secret and the value is 12 to 256 charactersx-custom-auth: …, session=…
9Your patternsRegexes from the config file
10IP addressesIPv4 (strictly validated) and IPv6, except loopback and unspecified203.0.113.9
11Base64Base64 or URL-safe base64 whose decoded text contains a secret. Images and other binary data are left alone.eyJhcGlfa2V5…
12Randomness detector16 to 128 character tokens that look machine-generated: mixed case or digits, high Shannon entropy, few vowels. UUIDs are exempt.an unknown vendor's key

Headers. Authorization, Cookie, Set-Cookie, X-Api-Key, Api-Key, X-Auth-Token and Proxy-Authorization are always redacted, plus any you add.

Vendor tiers. Matching all prefixes the same way would redact ordinary words, so they are tiered:

TierNeeds after the prefixExamples
Strong16+ token characterssk-ant-, sk-proj-, AKIA, ASIA, ghp_, github_pat_, glpat-, xoxb-, sk_live_, sk_test_, rk_live_, npm_, SG., AIza, ya29., pplx-
Weak (also occur in normal words)20+ characters, plus a digit, a capital or 24+ charactershf_, r8_, secret_, api_key_, access_token_, bearer , token
Connection strings8+ characterspostgres://, mysql://, mongodb+srv://, redis://, amqp://

Prefixes are matched case-sensitively, so asiapacific_region is left alone.

Bodies are decoded before scrubbing. gzip and deflate (up to 1 MiB expanded, a decompression-bomb guard). multipart/form-data forms are split into fields; file parts keep only the field name, file name and size.


🛡️ Safety shields

ShieldBehaviour
Request shieldA request body with a Content-Encoding NullWire can't read (br, zstd, stacked encodings) is refused with 415, because a body that can't be scrubbed must not reach the model. -allow-uninspectable forwards such requests anyway.
Response shieldThe client's Accept-Encoding is cut down to gzip and deflate before it reaches the server, so servers never answer in Brotli or Zstd. A client that offers nothing usable gets identity.
Unreadable bodiesAny other encoded body is stored as a short placeholder with a visible warning in the flow's note.
Protobuf and gRPCBinary bodies are not stored. Only their size is recorded.
Size limitsSee the table below. A secret that straddles a limit is still scrubbed first, thanks to an 8 KiB scrub window.
Loopback onlyThe proxy binds to 127.0.0.1. The reverse gateway answers only loopback Host headers (403 otherwise) and refuses to proxy to itself (508).
Tunnel limitsAt most 256 concurrent tunnels and upgraded connections, each closed after 10 minutes idle.
Wipe on exitSIGINT and SIGTERM clear the ring buffer before the process exits.

Limits

WhatLimit
Flows kept in RAM50
Stored request body32 KiB
Stored response body256 KiB
In-flight capture buffer64 KiB request, 512 KiB response
Scrub window past the stored size8 KiB
Decoded gzip/deflate1 MiB
Randomness detector16 to 128 characters

⚙️ Configuration

Pass -secrets-config path/to/file.json to tune redaction without recompiling. Every field is optional.

json
{  "sensitive_headers":     ["X-Company-Auth", "X-Api-Signature"],  "ignore_url_substrings": ["/healthz", "/metrics"],  "ignore_headers":        ["User-Agent"],  "custom_vendors": [    { "name": "Internal DB", "prefix": "db_prod_", "pattern": "" },    { "name": "Acme Auth",   "prefix": "acme_",    "pattern": "acme_[a-zA-Z0-9]{32}" }  ],  "extra_regex_patterns": [    { "name": "app_key", "pattern": "app_k_[a-zA-Z0-9]{24}" }  ]}
FieldEffect
sensitive_headersHeader values that are always redacted, like Authorization. -scrub-headers a,b adds more from the command line.
ignore_url_substringsFlows whose URL contains one of these are never recorded (health checks, metrics).
ignore_headersHeader values that are left as they are.
custom_vendorsprefix redacts anything with 8+ token characters after it. pattern is an optional full regex.
extra_regex_patternsExtra regexes; every match is redacted.

Patterns use Go's RE2 syntax, which runs in linear time, so a bad pattern cannot freeze the proxy.


🔌 Connect your MCP clients: install

install writes NullWire into your MCP clients' config files, and removes it again, so you never have to hunt for the right file or JSON key.

bash
nullwire-mcp install --list                          # supported clients and whether they are herenullwire-mcp install --client all --dry-run          # preview every changenullwire-mcp install --client cursor,vscode          # just these twonullwire-mcp install --client cursor -- -port 8081   # save server flags with the entry (after --)nullwire-mcp install --uninstall --client all        # take it back outnullwire-mcp install --print                         # a snippet to paste into clients that aren't supported
Client--clientWhat it edits
Claude Desktopclaude-desktopclaude_desktop_config.json in your user config folder
Claude Codeclaude-coderuns claude mcp add --scope user (needs the claude command)
Cursorcursor~/.cursor/mcp.json
Windsurfwindsurf~/.codeium/windsurf/mcp_config.json
VS Code (Copilot)vscodeyour user mcp.json
Clineclinecline_mcp_settings.json
Roo Coderoomcp_settings.json
Gemini CLIgemini~/.gemini/settings.json
Codex CLIcodex~/.codex/config.toml ([mcp_servers.nullwire])

Other clients (Zed, Continue, JetBrains and more) are not edited. Use --print and paste the snippet where that client keeps its MCP servers.

How it stays safe

  • With --client all it only touches clients it finds on your machine. Name a client explicitly to create its config.
  • The first time it changes a file it keeps a copy next to it as <file>.nullwire-bak. That copy is never overwritten, so it always holds the original.
  • Files are written through a temporary file and renamed, and symlinked dotfiles stay symlinks.
  • Your other servers, settings, numbers and extra fields on the NullWire entry (such as env) are kept. JSON keys may be re-ordered.
  • A config it can't parse as plain JSON (for example one with comments) is left alone, with a clear message.
  • Running it twice changes nothing the second time.
OptionMeaning
--clientComma-separated client ids, or all (default).
--nameName to register the server under (default nullwire).
--binary PATHRegister this binary instead of the one that is running.
--npxRegister npx -y nullwire-mcp (used automatically when you started it through npx).
--dry-run, --uninstall, --list, --printAs described above.
-- …Everything after -- is saved as the server's own flags.

🔎 Scan your machine: scan and protect

Secrets leak long before traffic does: a token in an MCP config, a password in .env. NullWire can find them. Scanning never writes to disk and never prints a secret: findings are shown already scrubbed, and shell history text is never shown at all.

bash
nullwire-mcp scan --discover                 # known MCP client configs, ~/.env, ~/.codex/config.toml, …nullwire-mcp scan .mcp.json .env             # specific filesnullwire-mcp scan --deep ./my-project --toml --yaml --zipnullwire-mcp scan --history                  # opt-in: count secrets in shell history
OptionMeaning
--discoverCheck the usual config locations under your home and config directories.
--deep DIRWalk a directory for MCP config JSON and .env files. Skips node_modules, .git, dist, build, vendor and similar by exact folder name.
--toml, --yaml, --zipAlso scan *.toml, *.yaml/*.yml and ZIP archives. Off by default so a deep scan doesn't open every CI file.
--historyCount lines with secrets in bash, zsh, fish and PowerShell history. Text is never printed.
exit codes0 done, 1 every file failed to scan, 2 bad usage

File types are recognised by name, so nullwire-mcp scan some.env config.toml settings.yaml bundle.zip routes each to the right scanner. Files over 4 MiB are skipped. ZIP archives are read in memory under a zip-bomb shield: entries over 1 MiB, archives over 20 MiB of content or 1000 entries are skipped and reported.

protect runs a quick scan of the usual places, then starts the normal server:

bash
nullwire-mcp protect --target https://api.example.com --deep .

It accepts the server options (--port, --target, --cacert, --dns, --secrets-config, --scrub-headers, --allow-uninspectable) plus --deep DIR, --history and --no-scan. The scan report goes to stderr, so the MCP channel on stdout stays clean, and stop signals are passed on to the server.


📟 CLI reference

text
nullwire-mcp [flags]                 run the MCP server and the proxynullwire-mcp scan [options] [PATH…]  look for secrets in filesnullwire-mcp protect [options]       scan, then run the servernullwire-mcp install [options]       register NullWire with your MCP clients
FlagDefaultMeaning
-port8080Proxy port. Always bound to 127.0.0.1.
-targetnoneReverse-gateway upstream: a URL and/or name=URL entries, comma-separated.
-cacertnoneExtra CA certificates (a PEM file or a directory) for upstream HTTPS.
-dnsautoUpstream DNS: auto, system, or a comma list of IPs such as 1.1.1.1,9.9.9.9:53.
-secrets-confignonePath to the JSON config.
-scrub-headersnoneExtra header names to always redact.
-allow-uninspectableoffForward request bodies that can't be inspected instead of refusing them with 415.

📱 Platform notes

Termux and Android. Static Go binaries have no system DNS settings or CA certificates on Android. NullWire detects Termux and uses 1.1.1.1 and 9.9.9.9 for lookups, printing a notice (those resolvers will see the hostnames you contact). Choose your own with -dns <resolver>, or -dns system to turn this off. Upstream HTTPS uses the CA certificates found in Termux's standard locations; add more with -cacert.

bash
chmod +x nullwire-linux-arm64sleep infinity | ./nullwire-linux-arm64   # keep stdin open; use a second session for curl

Corporate networks. If your company re-signs HTTPS traffic, add its root with -cacert /path/to/company-root.pem.

Windows. Use the .exe and the same flags. scan --history also checks PowerShell's PSReadLine history.


🔐 Security model and honest limits

NullWire is a diagnostic tool. Be clear-eyed about what it does and does not promise.

What it guarantees

  • Nothing is written to disk by the server, and a stop signal wipes memory. The install command edits MCP client configs only when you run it, and backs each file up first.
  • The proxy is reachable only from your own machine.
  • The model never sees the live traffic, only the scrubbed copy.
  • Live traffic is never rewritten, so what you debug is what runs.

What it does not do

  • Release binaries carry signed build provenance, not OS-vendor code-signing certificates. Verify authenticity with SHA256SUMS.txt and gh attestation verify. Because they are not signed with an Apple Developer ID or Microsoft Authenticode certificate, on macOS you may need xattr -d com.apple.quarantine ./nullwire-darwin-arm64.
  • It is not a TLS interceptor. CONNECT tunnels show only the destination and byte counts. Use the reverse gateway when you need HTTPS content.
  • Redaction is pattern and heuristic based. A secret in a shape nobody anticipated, and low in randomness, can slip through. The randomness detector can also redact a harmless long identifier. Add your own patterns in the config for secrets you know about.
  • Brotli and Zstd bodies are never decoded (the standard library can't, and pulling in a package would break the zero-dependency rule). They are refused (requests) or flagged (responses).
  • WebSocket flows appear when the connection closes. Messages compressed with permessage-deflate can't be read, so NullWire drops the client's extension offer to keep frames readable.
  • An XML secret element that contains nested markup is not covered by the XML layer.
  • Upstream connections use HTTP/1.1. HTTP/2 and gRPC bodies are not captured.

If you find a secret NullWire missed, please open an issue with a fake sample that has the same shape. Never post a real one.


✅ Tested on

PlatformStatusWhat was run
Linux x86-64 (Ubuntu 24.04)✅ verifiedgo vet, unit tests with -race, smoke test, end-to-end redaction
macOS 15 (Apple Silicon)✅ verifiedsmoke test, silent notifications, end-to-end redaction
macOS 15 (Intel)✅ verifiedsmoke test, silent notifications, end-to-end redaction
Windows x86-64✅ verifiedsmoke test, silent notifications, end-to-end redaction
Windows ARM64✅ verifiedsmoke test, silent notifications, end-to-end redaction
FreeBSD amd64 (VM)✅ verifiedsmoke test, silent notifications, end-to-end redaction
Linux ARMv7 (QEMU)🟡 emulatedsmoke test, silent notifications, end-to-end redaction
Linux RISC-V 64 (QEMU)🟡 emulatedsmoke test, silent notifications, end-to-end redaction
Linux ARM64 (Android / Termux)✅ verified on devicelive upstream proxy, redaction tags, export_sanitized_curl, reverse gateway, guards (needs termux-chroot)

🟡 emulated means run under QEMU, not on real hardware. Details are in docs/test-results.md.


🧪 Development

bash
go vet ./...go test -race ./...
  • Zero dependencies: go.mod has no require lines, and CI keeps it that way.
  • Release transparency: every release is built with Go 1.26 and includes SHA256SUMS.txt, a CycloneDX SBOM (nullwire-sbom.cdx.json) and a signed build provenance attestation, which you can verify with gh attestation verify. The same proof is attached to each release as nullwire-provenance.intoto.jsonl. The go vet and go test -race logs of every CI run are saved as a test-logs artifact for 30 days. Pushes to main update a rolling latest pre-release; numbered tags produce stable releases. Pull requests never publish anything.
  • Fuzzing: the scrubber, the IPv6 and vendor-key matchers and the WebSocket frame reader have fuzz targets. They check that no secret survives scrubbing, that results don't depend on how input is chunked, and that nothing panics.
  • CI: checks the shell and Node installers for syntax errors, runs go vet and the race detector, cross-compiles static binaries for all 9 platforms (Linux x86-64, ARM64, ARMv7 and RISC-V 64; macOS Intel and Apple Silicon; Windows x86-64 and ARM64; FreeBSD x86-64), and publishes a multi-arch Docker image (amd64 and arm64). smoke.yml and smoke-extra.yml run on demand (Actions → Run workflow): end-to-end redaction tests on Ubuntu, macOS (Apple Silicon and Intel), Windows (x86-64 and ARM64), a FreeBSD VM, and QEMU-emulated Linux ARMv7 and RISC-V 64. Security checks run govulncheck and the fuzz targets. GitHub Actions are pinned to full commit hashes.
Project layout
FilePurpose
main.goProxy, scrubber, ring buffer, MCP server and CLI
ws.goWebSocket frame reader and capture (read-only taps)
inspect.goRequest shield, multipart scrubbing, Accept-Encoding and protobuf rules
scrub_extra.goJSON array, XML and base64 redaction
vendors.goVendor prefix tiers
scan.go, env_scan.go, toml_scan.go, yaml_scan.go, zip_scan.go, history_scan.goThe scan command
protect.go, protect_helpers.goThe protect command
install.goThe install command (client config editing)
scripts/install.sh, scripts/install.ps1Installers for macOS, Linux, Termux and Windows
npm/The npx launcher (no dependencies, no install script)
packaging/Homebrew and Scoop templates and render.sh
feature_test.goTests for the features above

❓ Troubleshooting

SymptomCause and fix
HTTPS shows only a CONNECT entryThat is the blind tunnel. Use the reverse gateway (-target) to see HTTPS requests.
415 Unsupported Media Type from NullWireYour client sent a request body compressed with br or zstd. Send it uncompressed or gzipped, or start with -allow-uninspectable.
403 reverse gateway only answers loopback Host headersReach the gateway as 127.0.0.1, localhost or [::1] on the proxy port.
certificate signed by unknown authority (Termux or a corporate network)Add the CA with -cacert.
A harmless value shows as [REDACTED_TOKEN#…]The randomness detector matched a long random-looking identifier. Add its URL to ignore_url_substrings or tell us the shape.
install says a config is "not plain JSON"The file has comments or a syntax error, so it was left untouched. Fix it, or use install --print and paste the entry yourself.
address already in useAnother NullWire (or program) uses the port. Pick another with -port.
The assistant sees no flowsCheck the status bar's RAM Ring: n/50. If it stays at 0, your traffic isn't going through the proxy.

Built by VoxNode-ux · Version 1.2.0 · License: see the repository's LICENSE file

If NullWire saved you from pasting a secret into a chat, a ⭐ helps others find it.

來源:README.md,提交 4eb9b0a

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

2
  1. v1.0.2最新Oct 29, 2026
  2. v1.0.0Oct 26, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分

其他 Wire 整合