ihciah/shadow-tls
A proxy to expose real tls handshake to the firewall
Healthy across all four use cases
weakest axisPermissive 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.
- ✓8 active contributors
- ✓MIT licensed
- ✓CI configured
Show all 6 evidence items →Show less
- ✓Tests present
- ⚠Stale — last commit 1y ago
- ⚠Single-maintainer risk — top contributor 87% of recent commits
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/ihciah/shadow-tls)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/ihciah/shadow-tls on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: ihciah/shadow-tls
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/ihciah/shadow-tls 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 all four use cases
- 8 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Stale — last commit 1y ago
- ⚠ Single-maintainer risk — top contributor 87% of recent commits
<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 ihciah/shadow-tls
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/ihciah/shadow-tls.
What it runs against: a local clone of ihciah/shadow-tls — 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 ihciah/shadow-tls | 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 ≤ 408 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of ihciah/shadow-tls. If you don't
# have one yet, run these first:
#
# git clone https://github.com/ihciah/shadow-tls.git
# cd shadow-tls
#
# 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 ihciah/shadow-tls and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "ihciah/shadow-tls(\\.git)?\\b" \\
&& ok "origin remote is ihciah/shadow-tls" \\
|| miss "origin remote is not ihciah/shadow-tls (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 "src/main.rs" \\
&& ok "src/main.rs" \\
|| miss "missing critical file: src/main.rs"
test -f "src/server.rs" \\
&& ok "src/server.rs" \\
|| miss "missing critical file: src/server.rs"
test -f "src/client.rs" \\
&& ok "src/client.rs" \\
|| miss "missing critical file: src/client.rs"
test -f "Cargo.toml" \\
&& ok "Cargo.toml" \\
|| miss "missing critical file: Cargo.toml"
test -f "src/lib.rs" \\
&& ok "src/lib.rs" \\
|| miss "missing critical file: src/lib.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 408 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~378d)"
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/ihciah/shadow-tls"
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
Shadow TLS is a TLS-masquerading proxy written in Rust that allows real TLS handshakes using third-party valid certificates (e.g., from major companies) without self-signed certs. It works like Trojan but exposes legitimate TLS traffic to firewalls by proxying the handshake while relaying application data, solving circumvention scenarios where encrypted proxies need plausible TLS cover. Dual-mode binary (client/server) with core logic split: src/client.rs handles client-side TLS initiation, src/server.rs manages server-side relay and handshake parsing, src/helper_v2.rs contains protocol logic, src/sip003.rs adds shadowsocks plugin interface. Tests in tests/ cover TLS variants (tls12.rs, tls13.rs, sni.rs). Config via JSON files (examples/client_config.json, examples/server_config.json).
👥Who it's for
Network engineers and privacy-focused users deploying censorship circumvention infrastructure who need to tunnel encrypted traffic (typically shadowsocks) through firewall inspection by presenting valid TLS certificates without owning the corresponding domain.
🌱Maturity & risk
Actively maintained and production-ready: v0.2.25 with GitHub Actions CI/CD pipeline, Docker support, comprehensive protocol documentation (v2 and v3), and integration tests for TLS 1.2/1.3/SNI. Single maintainer (ihciah) but consistent recent activity suggests active development.
Medium risk: relies on a high-performance async runtime (Monoio with io_uring) that doesn't support Windows and requires system configuration tweaks; uses a forked version of rustls (monoio-rustls-fork-shadow-tls v0.3.0-mod.2) which introduces supply chain fragility; no indication of formal security audit. Small dependency surface (~15 direct deps) mitigates some risk.
Active areas of work
Active maintenance with release CI/CD pipeline (.github/workflows/build-release.yml) building binaries. Protocol v3 documentation added alongside v2, indicating ongoing protocol iteration. Monoio runtime dependency (v0.2.0) tracks a high-performance async ecosystem.
🚀Get running
git clone https://github.com/ihciah/shadow-tls.git
cd shadow-tls
cargo build --release
./target/release/shadow-tls client --help
# OR use docker-compose:
docker-compose up -d
Daily commands:
# Client (connects through firewall):
./shadow-tls client --config examples/client_config.json
# Server (receives from client):
./shadow-tls server --config examples/server_config.json
# With legacy epoll driver (no io_uring):
MONOIO_FORCE_LEGACY_DRIVER=1 ./shadow-tls server --config examples/server_config.json
🗺️Map of the codebase
src/main.rs— Entry point for the application; initializes client/server modes and configuration parsing—every contributor must understand the mode selection logic.src/server.rs— Core server-side TLS proxy implementation that performs real TLS handshakes and relays traffic—essential for understanding the server data flow.src/client.rs— Core client-side proxy that initiates connections and performs upstream TLS handshakes—critical for understanding client-server communication.Cargo.toml— Declares dependencies on custom rustls and monoio forks, which are non-standard and critical to Shadow TLS's unique TLS interception capability.src/lib.rs— Exports public API and shared utilities; serves as the module root for understanding the crate's interface.src/sip003.rs— Implements SIP003 plugin interface for shadowsocks integration—necessary for understanding how Shadow TLS integrates with the broader proxy ecosystem.docs/protocol-v3-en.md— Documents the v3 protocol specification and handshake semantics—essential reference for protocol-level debugging and feature additions.
🧩Components & responsibilities
- main.rs (clap, anyhow, ctrlc) — Parses CLI arguments and configuration files; dispatches to client or server mode; orchestrates graceful shutdown.
- Failure mode: Invalid configuration or missing arguments; logs error and exits.
- server.rs (monoio, rustls-) — Listens for client connections, performs real TLS handshake with target server, relays encrypted traffic bidirectionally, and enforces authentication.
🛠️How to make changes
Add Support for a New Configuration Option
- Define the new field in the configuration struct (typically in main.rs or a config module) (
src/main.rs) - Update the example JSON configuration files to include the new option (
examples/server_config.json) - Implement the configuration parsing logic and apply the option in server.rs or client.rs (
src/server.rs) - Add integration test to verify the new configuration option is correctly parsed and applied (
tests/tls13.rs)
Implement a New Protocol Version
- Create a new helper module (e.g., src/helper_v3.rs) following the pattern of helper_v2.rs for cryptographic operations (
src/helper_v2.rs) - Add protocol version selection logic in server.rs based on handshake message inspection (
src/server.rs) - Implement corresponding client-side protocol handling in client.rs (
src/client.rs) - Write protocol specification in docs/ directory (e.g., docs/protocol-v4-en.md) and add integration tests (
docs/protocol-v3-en.md)
Add a New Cryptographic Hash or HMAC Algorithm
- Add the new algorithm dependency to Cargo.toml (e.g., blake3, sha3) (
Cargo.toml) - Implement the algorithm wrapper in helper_v2.rs or create a new helper module following existing patterns (
src/helper_v2.rs) - Update server.rs and client.rs to select and use the new algorithm based on configuration or protocol negotiation (
src/server.rs) - Add test cases in tests/ directory to validate the new algorithm's correctness (
tests/utils.rs)
🔧Why these technologies
- Custom rustls fork (monoio-rustls-fork-shadow-tls) — Enables direct TLS handshake interception without certificate management; allows using target server's legitimate certificate by directly controlling the handshake flow.
- Monoio (async runtime with sync features) — Provides non-blocking I/O for efficient handling of multiple concurrent proxy connections without per-connection threads.
- HMAC-SHA1/SHA2 (helper_v2.rs) — Implements protocol-level authentication and integrity checks between client and server without full encryption, allowing TLS to handle encryption.
- Docker + Docker Compose — Simplifies deployment of the two-component system (Shadow TLS + shadowsocks) in containerized environments.
⚖️Trade-offs already made
-
No built-in encryption; relies on pairing with shadowsocks or similar proxy
- Why: Shadow TLS focuses solely on TLS handshake interception to fool firewalls; data encryption is delegated to companion proxies to keep the codebase focused.
- Consequence: Must be deployed as part of a larger proxy stack; cannot be used standalone for encrypted tunneling.
-
Custom rustls fork instead of vanilla rustls
- Why: Vanilla rustls does not expose the low-level TLS handshake control needed to perform real handshakes with arbitrary target certificates.
- Consequence: Maintenance burden of tracking upstream rustls changes; potential incompatibility with standard rustls ecosystem.
-
Protocol-level authentication (HMAC) instead of TLS-based security
- Why: TLS certificate validation would fail when connecting to arbitrary targets; HMAC-based authentication is lightweight and sufficient for the use case.
- Consequence: Clients must possess pre-shared keys or credentials; no certificate pinning beyond the real TLS handshake to the target.
🚫Non-goals (don't propose these)
- Does not provide end-to-end encryption of payload data (delegates to shadowsocks or similar).
- Does not implement certificate signing or CA management (uses real certificates from target servers).
- Does not support Windows natively (no Windows binaries; Docker or WSL required).
- Does not implement DNS resolution (relies on configuration-provided addresses).
- Does not provide rate limiting, bandwidth throttling, or traffic shaping.
- Does not implement socks5 or http proxy protocols (TLS-only).
🪤Traps & gotchas
- Monoio io_uring requirement: Needs Linux io_uring support or fallback via MONOIO_FORCE_LEGACY_DRIVER=1 env var; no Windows support. 2. System limits: May require
ulimit -l unlimited(memlock) to function—see Monoio docs/en/memlock.md. 3. Forked dependencies: rustls-fork-shadow-tls v0.20.9-mod.2 is a custom fork; upstream rustls updates won't auto-apply. 4. Certificate pinning: Server config expects real valid certificate from SNI target; self-signed won't work. 5. Async-only: No sync APIs; stdlib blocking calls will panic on Monoio.
🏗️Architecture
💡Concepts to learn
- TLS Handshake Interception & Relay — Core to shadow-tls: must detect when real TLS handshake completes (ClientHello→ServerHello→finished) so relay can switch from parsing to opaque passthrough without re-encrypting.
- Server Name Indication (SNI) — Mechanism to spoof TLS to third-party domains; shadow-tls extracts SNI from ClientHello, uses it to request real cert, allowing firewall inspection to see legitimate certificate chains.
- io_uring Linux I/O subsystem — Underlying I/O multiplexer in Monoio runtime; shadow-tls's zero-copy relay efficiency depends on io_uring's async syscall batching; fallback to epoll available but slower.
- Shadowsocks Plugin Interface (SIP003) — Standardized env-var protocol for chaining proxies; shadow-tls implements SIP003 (src/sip003.rs) to work transparently with shadowsocks-rust as an obfuscation layer.
- TLS Record Framing & Parsing — Must parse opaque TLS records (Content-Type, Version, Length) to identify handshake boundaries without decryption; helper_v2.rs contains state machine for this.
- Bidirectional Relay Pattern — After handshake detection, shadow-tls enters transparent relay mode; on Monoio this uses two async tasks for full-duplex copy without buffering (zero-copy if io_uring available).
- Firewall Circumvention via Certificate Reuse — Core threat model: firewall inspects TLS certificates; shadow-tls presents real certs (borrowed from google.com, etc.) making traffic appear legitimate while tunneling alternate data underneath.
🔗Related repos
trojan-gfw/trojan— Direct functional predecessor: similar proxy-in-TLS concept but requires self-signed certs; shadow-tls improves by using valid third-party certs.shadowsocks/shadowsocks-rust— Companion encryption layer: shadow-tls typically runs upstream of shadowsocks-rust to provide TLS obfuscation before encrypted tunnel.bytedance/monoio— Runtime dependency: high-performance io_uring async runtime that shadow-tls is built on; understanding Monoio helps debug performance issues.rustls/rustls— TLS library base: shadow-tls uses a fork (monoio-rustls-fork-shadow-tls); changes to upstream rustls may require rebasing the fork.ihciah/ful— Same maintainer's async proxy library; may share patterns for connection handling and relay logic with shadow-tls.
🪄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 integration tests for SIP003 plugin protocol in src/sip003.rs
The repo has src/sip003.rs but lacks dedicated tests for the SIP003 (shadowsocks plugin) protocol implementation. The existing tests directory (tests/) only covers TLS handshakes (tls12.rs, tls13.rs, sni.rs) but not the plugin integration layer. This is critical since SIP003 is the standard protocol for shadowsocks plugins and needs comprehensive coverage for client/server plugin communication.
- [ ] Create tests/sip003.rs with test cases for SIP003 protocol parsing and validation
- [ ] Add tests for plugin parameter passing and environment variable handling
- [ ] Test SIP003 request/response serialization used in src/sip003.rs
- [ ] Add tests for error handling when SIP003 protocol is malformed
- [ ] Reference src/sip003.rs implementation to ensure all code paths are covered
Add GitHub Actions workflow for cross-platform binary releases and artifact signing
The repo has build-release.yml workflow but lacks explicit cross-compilation targets and binary artifact integrity verification. Given the security-sensitive nature of a proxy tool, users need pre-built binaries for multiple platforms (x86_64-unknown-linux-gnu, x86_64-pc-windows-gnu, aarch64-unknown-linux-gnu, etc.) with SHA256 checksums and ideally GPG signatures to verify download integrity.
- [ ] Extend .github/workflows/build-release.yml to include cross-compilation targets using cross-rs or rustup
- [ ] Generate SHA256 checksums for each compiled binary artifact
- [ ] Upload checksums alongside release binaries
- [ ] Consider adding GPG signing step for release artifacts (optional but recommended for security tools)
- [ ] Add automated test runs on the compiled binaries to verify functionality pre-release
Implement unit tests for TLS protocol edge cases in src/client.rs and src/server.rs
The current tests (tls12.rs, tls13.rs, sni.rs) test basic handshake scenarios but the core client.rs and server.rs implementations lack unit tests for error handling, connection state transitions, and malformed packet handling. This is especially important given shadow-tls's role in exposing real TLS handshakes to firewalls—edge cases matter.
- [ ] Add unit tests in tests/client.rs for client-side connection failures, timeouts, and invalid peer certificates
- [ ] Add unit tests in tests/server.rs for server-side handling of incomplete handshakes and protocol violations
- [ ] Test the helper_v2.rs protocol layer with both valid and invalid payloads
- [ ] Add tests for concurrent connection handling in monoio runtime (src/client.rs and src/server.rs use monoio)
- [ ] Reference util.rs utility functions to ensure edge cases around buffer handling are covered
🌿Good first issues
- Add unit tests for src/util.rs—currently no dedicated tests, should cover byte parsing and encoding functions used in protocol.
- Document the SIP003 environment variables in README—src/sip003.rs integrates with shadowsocks but README doesn't explain required env setup (e.g., SS_LOCAL_HOST, SS_REMOTE_HOST).
- Add example docker-compose for TLS 1.3 + SNI scenario—docker-compose.yml exists but examples/ lacks annotated compose files showing realistic client→proxy→real_server topology with logging.
⭐Top contributors
Click to expand
Top contributors
- @ihciah — 45 commits
- @VendettaReborn — 1 commits
- @UjuiUjuMandan — 1 commits
- @erfan-khadem — 1 commits
- @WoLuo-dev — 1 commits
📝Recent commits
Click to expand
Recent commits
02dd0bc— fix: use tls1.2 only website for tls12 test suites (#129) (VendettaReborn)0450141— Fix reading WildcardSNI from sip003_arg (#115) (UjuiUjuMandan)dee3a5a— chore: update depencencies (ihciah)3f4d312— feat: resolve domain with spawn_blocking (ihciah)5484ecc— Feat: Add config file support (#90) (erfan-khadem)5454cb4— feat: use monoio 0.1.3 and support TCP_FASTOPEN (ihciah)f359305— fix: fix workflow download path (ihciah)f13cefd— chore: build docker from release binary for faster and armv7l support (ihciah)5191766— chore: better tests (ihciah)7163cdd— adjust to new nightly toolchain (ihciah)
🔒Security observations
- High · Forked and Modified TLS Libraries —
Cargo.toml - dependencies section. The project uses custom-forked versions of rustls and monoio-rustls libraries (monoio-rustls-fork-shadow-tls and rustls-fork-shadow-tls). These forks deviate from upstream security patches and may not receive timely security updates. The modifications could introduce vulnerabilities or bypass important security checks in the TLS implementation. Fix: Evaluate whether custom forks are necessary. If modifications are required, establish a process to regularly backport security patches from upstream. Consider contributing changes back to upstream projects. Implement automated security scanning of forked dependencies. - High · Outdated Rust Toolchain —
Dockerfile - FROM rust:1.74-alpine, rust-toolchain file. The Dockerfile uses Rust 1.74-alpine which is significantly outdated (released October 2023). This may miss critical security patches and compiler-level security improvements. The rust-toolchain file specifies an older version without pinning. Fix: Update to the latest stable Rust version (1.75+). Pin exact Rust versions in rust-toolchain for reproducibility. Implement automated dependency updates with CI/CD testing. - High · Weak Container Base Image —
Dockerfile - FROM alpine:latest. The final Docker image uses alpine:latest without a specific version tag. Using 'latest' tag makes builds non-reproducible and vulnerable to breaking changes. Additionally, Alpine's minimal nature means fewer security patches may be applied compared to other distributions. Fix: Pin the Alpine version to a specific release (e.g., alpine:3.19). Implement image scanning in CI/CD pipeline. Use --no-cache flag during package updates to ensure latest security patches. - Medium · Missing Input Validation in Configuration —
docker-compose.yml, entrypoint.sh, Dockerfile ENV declarations. The docker-compose.yml and entrypoint.sh expose multiple environment variables (MODE, LISTEN, SERVER, TLS, PASSWORD, etc.) without apparent validation. Environment variables are directly passed to the application without sanitization, which could lead to injection attacks or unexpected behavior. Fix: Implement strict input validation in entrypoint.sh for all environment variables. Define allowed formats and reject invalid inputs. Use a configuration validation library in the Rust code. Document expected formats for each environment variable. - Medium · TLS Certificate Verification Bypass Risk —
README.md, src/client.rs, src/server.rs. The project's purpose is to expose 'real' TLS handshakes using borrowed certificates. While this is by design, the implementation could potentially be misused to perform MITM attacks. The documentation mentions using certificates from 'other people' or 'big companies', which raises concerns about certificate misuse. Fix: Add explicit warnings in documentation about legal and ethical implications. Implement certificate pinning options for client validation. Consider adding audit logging for certificate usage. Require explicit acknowledgment of Terms of Service regarding certificate usage. - Medium · Network Mode 'Host' in Docker Compose —
docker-compose.yml - network_mode setting. The docker-compose.yml uses network_mode: 'host', which exposes the container directly to the host network without isolation. This increases the attack surface and potential for lateral movement in case of a compromise. Fix: Use bridge networking with explicit port mappings instead of host mode. If host mode is necessary, document the security implications and use network policies/firewall rules. Restrict container capabilities using security_opt and cap_drop. - Medium · Insufficient Dependency Version Pinning —
Cargo.toml - [dependencies] section. Most dependencies use loose version specifications (e.g., 'anyhow = "1"', 'clap = "4"') which could allow updates to versions with security vulnerabilities. Only cryptographic libraries are specified with precision, leaving other dependencies vulnerable to transitive dependency attacks. Fix: Use Cargo.lock file for deterministic builds (already present). Consider using cargo-deny to audit dependencies. Implement automated dependency scanning with tools like cargo-audit. Regularly run 'cargo update' in controlled environments and test thoroughly. - Low · Missing Security Headers and Best Practices in Docker —
undefined. The Dockerfile doesn't implement several Docker security best practices: no USER directive (runs as root), no health checks, no read Fix: undefined
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.