jpillora/chisel
A fast TCP/UDP tunnel over HTTP
Healthy across the board
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 1w ago
- ✓25+ active contributors
- ✓Distributed ownership (top contributor 36% of recent commits)
Show 3 more →Show less
- ✓MIT licensed
- ✓CI configured
- ✓Tests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/jpillora/chisel)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/jpillora/chisel on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: jpillora/chisel
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/jpillora/chisel shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 1w ago
- 25+ active contributors
- Distributed ownership (top contributor 36% of recent commits)
- MIT licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live jpillora/chisel
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/jpillora/chisel.
What it runs against: a local clone of jpillora/chisel — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in jpillora/chisel | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 39 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of jpillora/chisel. If you don't
# have one yet, run these first:
#
# git clone https://github.com/jpillora/chisel.git
# cd chisel
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of jpillora/chisel and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "jpillora/chisel(\\.git)?\\b" \\
&& ok "origin remote is jpillora/chisel" \\
|| miss "origin remote is not jpillora/chisel (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "main.go" \\
&& ok "main.go" \\
|| miss "missing critical file: main.go"
test -f "client/client.go" \\
&& ok "client/client.go" \\
|| miss "missing critical file: client/client.go"
test -f "server/server.go" \\
&& ok "server/server.go" \\
|| miss "missing critical file: server/server.go"
test -f "share/tunnel/tunnel.go" \\
&& ok "share/tunnel/tunnel.go" \\
|| miss "missing critical file: share/tunnel/tunnel.go"
test -f "share/cnet/conn_ws.go" \\
&& ok "share/cnet/conn_ws.go" \\
|| miss "missing critical file: share/cnet/conn_ws.go"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 39 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~9d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/jpillora/chisel"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Chisel is a fast TCP/UDP tunnel that runs over HTTP and secures connections via SSH (using Go's crypto/ssh). It's a single executable that acts as both client and server, designed primarily for penetrating firewalls and establishing secure network endpoints by wrapping arbitrary traffic inside HTTP payloads. Monolithic CLI application: main.go drives both client/ and server/ packages which share common utilities in share/ (crypto, networking, tunneling, configuration). share/tunnel/ handles the core tunneling logic with separate paths for proxy (tunnel_in_proxy.go), SSH (tunnel_out_ssh.go), and UDP (tunnel_in_proxy_udp.go). Configuration lives in share/settings/ with user/auth management.
👥Who it's for
Network engineers, penetration testers, and DevOps professionals who need to tunnel traffic through restrictive firewalls, provide secure remote access to internal services, or set up reverse port forwarding without exposing services directly to the internet.
🌱Maturity & risk
Production-ready and actively maintained. The project demonstrates maturity through comprehensive CI/CD in .github/workflows/ci.yml, goreleaser-based releases, Docker distribution, and Fedora package integration. Recent Go 1.25 toolchain adoption and active dependabot integration suggest ongoing maintenance.
Low risk for core functionality but moderate dependency surface: relies on 9 external packages including golang.org/x/crypto, gorilla/websocket, and armon/go-socks5. Single-maintainer structure (jpillora) is a minor concern for long-term sustainability, though the codebase is mature and relatively stable.
Active areas of work
Active development with Go 1.25 toolchain adoption and dependency management via dependabot.yml. The .github/goreleaser.yml and multi-platform CI suggest ongoing release engineering. Example deployments exist (Flyfile, fly.toml) suggesting Fly.io integration work.
🚀Get running
git clone https://github.com/jpillora/chisel.git
cd chisel
make
./chisel --help
Or pre-built: curl https://i.jpillora.com/chisel! | bash or docker run jpillora/chisel --help
Daily commands:
Server: ./chisel server --port 8080. Client: ./chisel client http://server:8080 3000:localhost:3000. Or via Docker: docker run jpillora/chisel server --port 8080. Build with: make (see Makefile for build targets).
🗺️Map of the codebase
main.go— Entry point for the CLI application; defines server/client mode routing and is the foundation for understanding how chisel starts.client/client.go— Core client logic for establishing tunnel connections; must understand this to add features like new tunnel types or authentication methods.server/server.go— Core server logic for accepting and routing tunnel connections; essential for understanding the reverse-tunnel and ACL architecture.share/tunnel/tunnel.go— Abstract tunnel interface and base implementation; this is the load-bearing abstraction for both client and server tunneling behavior.share/cnet/conn_ws.go— WebSocket connection wrapper over HTTP; critical for understanding how the HTTP transport layer works.share/settings/config.go— Configuration parsing and validation; required to understand how CLI flags, environment variables, and remote settings are unified.server/server_handler.go— HTTP request handler for tunnel streams; essential for understanding request routing and authentication enforcement.
🛠️How to make changes
Add a new tunnel type or transport mode
- Define a new tunnel handler in share/tunnel/ by implementing the Tunnel interface (dial, close, etc.) (
share/tunnel/tunnel.go) - Register the new tunnel type in server_handler.go's switch statement for protocol dispatch (
server/server_handler.go) - Update client_connect.go to initiate the tunnel type when parsing remote specifications (
client/client_connect.go) - Add corresponding E2E test in test/e2e/ to validate the new tunnel behavior (
test/e2e/base_test.go)
Add a new authentication method
- Extend share/settings/user.go to support additional credential types (e.g., OAuth, mTLS) (
share/settings/user.go) - Modify server_handler.go to validate credentials before accepting tunnel streams (
server/server_handler.go) - Update client_connect.go to send new auth credentials during the handshake (
client/client_connect.go) - Add authentication test cases in test/e2e/auth_test.go (
test/e2e/auth_test.go)
Modify configuration options or add new flags
- Add new flag struct field in share/settings/config.go and define CLI parsing logic (
share/settings/config.go) - Update main.go to pass configuration to client or server constructors (
main.go) - Use the configuration value in the appropriate handler (client.go, server.go, or specific handler files) (
client/client.go) - Add a configuration test in test/e2e/setup_test.go if the setting affects startup behavior (
test/e2e/setup_test.go)
Extend ACL or access control rules
- Expand share/settings/users.go to support group-based or attribute-based ACL entries (
share/settings/users.go) - Update server_handler.go to evaluate new ACL conditions before permitting tunnel streams (
server/server_handler.go) - Add ACL test scenarios in test/e2e/acl_channel_test.go (
test/e2e/acl_channel_test.go)
🔧Why these technologies
- Go (golang) — Single-executable cross-platform binary; concurrent goroutines for handling multiple tunnels efficiently; strong standard library for cryptography and networking
- HTTP + WebSocket (RFC 6455) — HTTP is firewall-friendly and widely allowed; WebSocket provides bidirectional, low-overhead framing over HTTP/1.1 or HTTP/2
- SSH protocol (crypto/ssh) — Industry-standard encryption and authentication; Go's standard library provides a robust, audited implementation
- SOCKS5 — Universal proxy protocol for routing arbitrary TCP/UDP traffic; allows chisel to act as a transparent proxy for third-party applications
⚖️Trade-offs already made
-
HTTP transport over raw TCP sockets
- Why: Makes tunnels compatible with standard HTTP infrastructure (proxies, load balancers, firewalls) and harder to block
- Consequence: Slight latency and overhead vs. raw TCP; requires framing and multiplexing logic in share/cnet/conn_ws.go
-
Single executable for both client and server
- Why: Simplifies deployment, versioning, and reduces attack surface (no version mismatch)
- Consequence: Larger binary; both modes are compiled in even if only one is used; adds conditional logic in main.go
-
SSH encryption but NOT end-to-end with local services
- Why: SSH protects tunnel transport; local services are assumed to be on trusted networks or the tunnel endpoints themselves
- Consequence: Traffic inside the tunnel is unencrypted; requires separate TLS for sensitive endpoints (e.g., databases)
-
Stateless server design with optional user/ACL file
- Why: Enables horizontal scaling and simplicity; file-based config avoids database dependency
- Consequence: No dynamic user management without restart; ACL changes require server reload; share/settings/users.go is read once at startup
🚫Non-goals (don't propose these)
- VPN (does not replace full network virtualization; only tunnels specific ports/protocols)
- TLS termination for local services (assumes services handle their own encryption if needed)
- Dynamic user management via API (configuration is static file-based)
- Load balancing or failover (single-path tunnels; client reconnects on failure)
- Network isolation between clients (all authenticated clients can access the same tunnels)
🪤Traps & gotchas
User authentication config required for authenticated mode: share/settings/users.go expects a JSON file with user credentials—omitting it silently allows unauthenticated access. SSH key fingerprint matching: clients must match server fingerprint (via -auth flag) or explicitly trust via first-use; incorrect fingerprints fail silently. Firewall NAT issues: UDP tunnels (via tunnel_in_proxy_udp.go) may fail behind restrictive NAT—TCP-only fallback required. WebSocket vs raw TCP mode: share/cnet/conn_ws.go and conn_rwc.go have different behavior; mode auto-detection can surprise users. Hot-reload via fsnotify: user config reload may not trigger for all filesystem events depending on OS (Windows support in signal_windows.go is limited).
🏗️Architecture
💡Concepts to learn
- SSH protocol tunneling (crypto/ssh) — Chisel uses Go's standard SSH library to secure tunnel content; understanding key exchange, channel multiplexing, and session management is essential to modify connection security
- WebSocket upgrade within HTTP — Chisel tunnels can upgrade HTTP connections to WebSocket (see
share/cnet/conn_ws.go) to bypass some firewalls; must understand Upgrade handshake and frame masking to debug transport issues - Port forwarding and SOCKS5 proxy protocol — Core feature relies on SOCKS5 (RFC 1928) and local port binding;
share/tunnel/tunnel_in_proxy.goandarmon/go-socks5integration require understanding CONNECT requests and address resolution - Exponential backoff reconnection — Client auto-reconnect uses
jpillora/backofflibrary; tuning reconnection behavior requires understanding backoff strategy, jitter, and max delay configuration - HTTP CONNECT tunneling — Chisel can tunnel through HTTP proxies using CONNECT method (
share/tunnel/tunnel_in_proxy.go); critical for firewall bypass scenarios - Reverse proxy and reverse port forwarding — Server can act as reverse proxy (
share/settings/remote.go) or reverse-forward ports from client; understanding HTTP request rewriting and connection ownership is essential for this feature - Deterministic random number generation — Chisel uses deterministic RNG in
share/ccrypto/determ_rand.gofor reproducible key generation; relevant for testing and security audit
🔗Related repos
inconshreveable/ngrok— Industry standard tunnel similar in concept; ngrok is closed-source but Chisel provides open-source HTTP-tunneling alternativegravitational/teleport— SSH-based network access with tunneling; Chisel is lighter-weight but Teleport offers RBAC and recording for enterprise securitymasterzen/simplehttp— Simpler HTTP tunnel alternative in Go; Chisel adds SSH security and UDP supportjpillora/backoff— Direct dependency for exponential backoff reconnection logic in clientjpillora/requestlog— Direct dependency for HTTP request logging on server side
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive end-to-end tests for UDP tunnel functionality
The repo has UDP support (share/tunnel/tunnel_in_proxy_udp.go, share/tunnel/tunnel_out_ssh_udp.go, share/tunnel/udp.go) but test/e2e/ lacks UDP-specific test coverage. Only socks_test.go exists for proxy testing. UDP tunneling is a complex feature that deserves dedicated E2E tests similar to existing auth_test.go and tls_test.go to ensure reliability across platforms.
- [ ] Create test/e2e/udp_tunnel_test.go with basic UDP echo/proxy tests
- [ ] Add UDP-specific test cases for bidirectional traffic, packet loss scenarios, and concurrent connections
- [ ] Reference share/tunnel/tunnel_in_proxy_udp.go and share/tunnel/tunnel_out_ssh_udp.go implementations
- [ ] Verify tests pass on Windows (share/cos/signal_windows.go suggests cross-platform complexity)
Add integration tests for WireGuard tunneling feature
The codebase includes WireGuard support (share/tunnel/wg.go with wg_test.go) but share/tunnel/wg_test.go only contains unit tests. There are no E2E tests validating WireGuard tunnel creation, key exchange, and actual traffic routing through WireGuard interfaces. This is a premium feature deserving E2E validation.
- [ ] Create test/e2e/wireguard_test.go for end-to-end WireGuard tunnel validation
- [ ] Add test cases for WireGuard peer configuration, tunnel establishment, and cross-peer communication
- [ ] Reference share/tunnel/wg.go implementation details
- [ ] Include tests for WireGuard + authentication combinations (similar to auth_test.go + tls_test.go patterns)
Add GitHub Actions workflow for security vulnerability scanning and dependency auditing
The repo has .github/workflows/ci.yml and uses dependabot.yml but lacks automated security scanning. With cryptographic components (share/ccrypto/), remote access capabilities, and external dependencies, adding GitHub Actions for vulnerabilities (via go vuln, Trivy, or similar) and license compliance would improve security posture and contributor confidence.
- [ ] Create .github/workflows/security.yml with Go vulnerability scanning (golang.org/x/vuln)
- [ ] Add Trivy or similar container image scanning referenced in .github/Dockerfile
- [ ] Configure license compliance checks for dependencies in go.mod
- [ ] Ensure workflow runs on PR and schedule (e.g., weekly) similar to existing CI patterns
🌿Good first issues
- Add integration tests for reverse tunneling (reverse port forwarding) in client_test.go—currently only basic client connection is tested, gaps exist for
tunnel_out_ssh.goverification - Document SOCKS5 mode configuration in README and add example config in example/ directory showing SOCKS upstream proxy setup matching
share/tunnel/tunnel_in_proxy.gocode - Add request/response metrics export (Prometheus format) by extending
share/cnet/meter.go—currently only internal counters exist, no HTTP endpoint exposes them
⭐Top contributors
Click to expand
Top contributors
- @jpillora — 36 commits
- @noahsbwilliams — 30 commits
- @dependabot[bot] — 5 commits
- @Copilot — 3 commits
- @jinncoder — 3 commits
📝Recent commits
Click to expand
Recent commits
b9d1219— Fix race in tunnel waitGroup causing negative counter panic (#586) (jpillora)44310b6— Enforce auth ACL on tunnel channels (jpillora)4df5fcf— Update deps and fix crypto/tls vulnerability (#578) (jpillora)57d2249— Update all dependencies (jpillora)d56938d— fix goreleaser (jpillora)864b1c0— Fix goreleaser Windows ARM32 builds and CI compatibility (jpillora)5ac1a22— Fix CI workflow Go version to match go.mod requirement (#572) (Copilot)8ce920a— Bump Go version to 1.25.1 and update all dependencies (#568) (Copilot)91d0f66— Fix CHISEL_KEY environment variable ignored when --keyfile not set (#571) (Copilot)ab8f06a— always test with latest stable (jpillora)
🔒Security observations
The Chisel project demonstrates reasonable security fundamentals with use of modern Go dependencies (golang.org/x/crypto, golang.org/x/net) and automated dependency management via Dependabot. However, several concerns exist: (1) The critical issue of using an ancient, unmaintained SOCKS5 library from 2016 that poses significant security risks, (2) Invalid Go toolchain version specification that requires correction, (3) Absence of security vulnerability disclosure policy, and (4) Limited visibility into cryptographic implementation details. The codebase does not appear vulnerable to common injection attacks (Go's type safety) or exposed credentials in obvious locations. Recommend prioritizing replacement of the SOCKS5 dependency, establishing a security.md policy, and validating the Go version configuration.
- Medium · Outdated Go Toolchain Version —
go.mod. The project specifies Go 1.25.7, which appears to be a future/invalid version. Go releases follow semantic versioning with versions like 1.21, 1.22, etc. This may indicate a typo or misconfiguration that could lead to unexpected behavior or use of unintended compiler versions. Fix: Update to a valid, stable Go version (e.g., go 1.23 or latest stable release). Verify the correct toolchain version matches the project's tested and supported versions. - Medium · Transitive Dependency with No Version Pin —
go.mod - github.com/armon/go-socks5. The dependency 'github.com/armon/go-socks5' uses an old git commit hash (e75332964ef5 from 2016). This unmaintained SOCKS5 library may contain unpatched security vulnerabilities. No active security updates are available for this package. Fix: Evaluate replacing with a maintained SOCKS5 library alternative or audit the SOCKS5 implementation for known vulnerabilities. Consider forking and maintaining the library if it's critical to the project. - Low · Missing Security Policy File —
Repository root. No SECURITY.md or security vulnerability disclosure policy file is present in the repository. This makes it difficult for security researchers to responsibly report vulnerabilities. Fix: Create a SECURITY.md file in the root directory with instructions for reporting security vulnerabilities, response timelines, and contact information. - Low · No SBOM or Dependency Audit Automation —
.github/dependabot.yml and CI configuration. While the repository uses dependabot.yml, there is no evidence of automated dependency security scanning or Software Bill of Materials (SBOM) generation in the CI/CD pipeline. Fix: Enable GitHub Dependabot alerts, add 'go mod tidy' checks to CI, and consider generating SBOMs using tools like syft for release artifacts. - Low · Potential Hardcoded Credentials in Example Files —
example/users.json. The example directory contains 'example/users.json' which may contain example credentials or user configurations. While these are marked as examples, reviewers should verify no real credentials are accidentally committed. Fix: Ensure example files use placeholder values only (e.g., 'password123' or '<PASSWORD>'). Use .gitignore to prevent accidental commit of real credential files. Add pre-commit hooks to scan for secrets. - Low · Missing Cryptographic Best Practices Documentation —
Documentation and security/crypto implementation files. While the project claims SSH-based encryption and uses golang.org/x/crypto, there is no documented security architecture or cryptographic practices document visible in the provided structure. Fix: Create a SECURITY_ARCHITECTURE.md documenting: key exchange mechanisms, cipher suites used, certificate pinning policies (if applicable), and security assumptions. Reference it in the README.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.