Threats tagged 'go'
730 threats
Most recently published first
| Severity | CVSS | Signals | Threat | Source | Published | Score and star |
|---|---|---|---|---|---|---|
| High | 8.8 | EPSS 0.4% | CVE-2026-1078110xJacky nginx-ui · Information Exposure High8.8EPSS 0.4%CVE Database V5CVE-2026-107811 A vulnerability in 0xJacky's nginx-ui versions 2.0.0 through 2.4.x allows authenticated users to access sensitive node tokens via specific API endpoints. These tokens can be used to bypass cross-node authentication, enabling impersonation of trusted nodes within the cluster. This can expose sensitive management operations such as configuration synchronization and service restart. The issue is resolved in version 2.5.0. | CVE Database V5 | ||
| High | 8.1 | EPSS 0.4% | CVE-2026-1078100xJacky nginx-ui · Link Following High8.1EPSS 0.4%CVE Database V5CVE-2026-107810 CVE-2026-107810 is a high-severity vulnerability in 0xJacky's nginx-ui versions from 2.0.0 up to but not including 2.5.0. It involves improper link resolution before file access in the backup and restore functionality, allowing an authenticated user with backup creation and restoration privileges to inject malicious symlinks. This can lead to persistent configuration injection or denial of service. The issue is fixed in version 2.5.0. | CVE Database V5 | ||
| High | 8.8 | EPSS 0.2% | CVE-2026-1078090xJacky nginx-ui · Cross-Site Request Forgery (CSRF) High8.8EPSS 0.2%CVE Database V5CVE-2026-107809 ## Summary Nginx-UI v2.4.3 stores the API JWT in a browser cookie named `token` and the `AuthRequired` middleware accepts that cookie as an authentication source. Because management endpoints are protected by `AuthRequired` and do not enforce a universal CSRF token or Origin/Referer check, a remote attacker can induce a logged-in administrator to submit cross-site state-changing requests. The attacker does not need to read the cross-origin response; the browser-sent cookie is enough to authenticate the request. ## Details The root cause is a trust-boundary failure between browser-managed cookies and API bearer-token authentication. In `app/src/pinia/moudule/user.ts:25-35`, the front end writes the JWT to a `token` cookie when the token changes. In `internal/middleware/middleware.go:16-36`, `getToken` first checks the `Authorization` header and `token` query parameter, then falls back to `c.Cookie("token")`. That fallback causes browser-initiated cross-site requests to carry a valid API credential automatically. The route group in `router/routers.go:87-110` applies `middleware.AuthRequired()` to many management modules, including `config.InitRouter`, `nginx.InitRouter`, `settings.InitRouter`, and backup-related handlers. For accounts without OTP/Passkey, `RequireSecureSession` does not provide a universal second factor for all state-changing operations. A representative sink is `api/config/add.go:68-78`, where an authenticated request writes Nginx configuration with `os.WriteFile` and then calls `nginx.Control(nginx.Reload)`. CORS does not mitigate this issue because preventing cross-origin response reads does not prevent cross-site form or no-cors requests from being sent with cookies. Core vulnerable code path: ```typescript // app/src/pinia/moudule/user.ts:25-35 watch(token, v => { if (v) { cookies.set('token', v, getCookieOptions(86400)) if (!shortToken.value) { void fetchShortToken() } } else { cookies.remove('token', { path: '/' }) shortToken.value = '' } }) ``` The front end stores the authentication token in a `token` cookie. The cookie is created client-side and is not shown here as HttpOnly; it becomes the credential that the back end later accepts through cookie fallback. ```go // internal/middleware/middleware.go:16-36 // getToken from header, cookie or query func getToken(c *gin.Context) (token string) { if token = c.GetHeader("Authorization"); token != "" { return } if token = c.Query("token"); token != "" { if len(token) > 16 { // Long token (base64 encoded JWT) tokenBytes, _ := base64.StdEncoding.DecodeString(token) return string(tokenBytes) } // Short token (16 characters) return token } if token, _ = c.Cookie("token"); token != "" { return token } return "" } ``` `getToken` accepts the `token` cookie as an authentication credential after checking the header and query parameter. That behavior lets a browser-sent cookie authenticate state-changing API requests triggered from another origin. ```go // router/routers.go:87-110 // Authorization required and not websocket request g := root.Group("/", middleware.AuthRequired(), middleware.Proxy()) { debug.InitRouter(g) user.InitUserRouter(g) analytic.InitRouter(g) user.InitManageUserRouter(g) nginx.InitRouter(g) sites.InitRouter(g) streams.InitRouter(g) config.InitRouter(g) template.InitRouter(g) certificate.InitCertificateRouter(g) certificate.InitDNSCredentialRouter(g) certificate.InitAcmeUserRouter(g) dnsapi.InitRouter(g) system.InitPrivateRouter(g) settings.InitRouter(g) llm.InitRouter(g) cluster.InitRouter(g) notification.InitRouter(g) external_notify.InitRouter(g) backup.InitAutoBackupRouter(g) nginxLog.InitRouter(g) upstream.InitHTTPRouter(g) ``` Many management modules, including Nginx, configuration, settings, backup, and user management, are placed behind `AuthRequired`. The cookie fallback therefore protects high-impact state-changing routes, not only read-only endpoints. ```go // api/config/add.go:68-78 err = os.WriteFile(path, []byte(content), 0644) if err != nil { cosy.ErrHandler(c, err) return } res := nginx.Control(nginx.Reload) if res.IsError() { res.RespError(c) return } ``` This representative sink shows why the CSRF is high impact: once authenticated through the cookie fallback, a request can write Nginx configuration content and trigger a reload. ## POC Prerequisites: an administrator is logged in to Nginx-UI and has a browser `token` cookie; the administrator account has not enabled OTP/Passkey, or the chosen target endpoint does not require secure-session proof; the attacker knows the Nginx-UI management URL and can induce the administrator to visit an attacker-controlled page. Reproduction: (1) Host an attacker page at `GET /csrf.html` that automatically submits a cross-site request to the victim instance. (2) The page submits `POST /api/configs` | CVE Database V5 | ||
| High | 8.1 | EPSS 0.4% | CVE-2026-1078080xJacky nginx-ui · Improper Authentication High8.1EPSS 0.4%CVE Database V5CVE-2026-107808 ## Summary nginx-ui supports two second-factor methods — TOTP (OTP) and WebAuthn passkeys — and reports an account as 2FA-enabled when **either** is configured. However, the password login endpoint (`POST /api/login`) only enforces a second factor when a **TOTP secret** is present. An account that has registered a **passkey but no TOTP** is logged in after password verification alone — the passkey is never requested. This silently downgrades a passkey-protected account to single-factor (password-only) authentication. ## Details The account's 2FA policy treats passkeys as a valid factor (`model/user.go`): ```go func (u *User) EnabledOTP() bool { return len(u.OTPSecret) != 0 } func (u *User) EnabledPasskey() bool { /* true if a passkey row exists */ } func (u *User) Enabled2FA() bool { return u.EnabledOTP() || u.EnabledPasskey() } func (u *User) AfterFind(_ *gorm.DB) error { u.EnabledTwoFA = u.Enabled2FA() // exposed to the UI as `enabled_2fa` return nil } ``` But the login handler only checks `EnabledOTP()` (`api/user/auth.go`, `Login`): ```go u, err := user.Login(json.Name, json.Password) ... if u.EnabledOTP() { // <-- only TOTP is enforced if json.OTP == "" && json.RecoveryCode == "" { c.JSON(http.StatusOK, LoginResponse{Message: "The user has enabled 2FA", Code: Enabled2FA}) // 199 user.BanIP(clientIP) return } if _, err = user.VerifyOTP(u, json.OTP, json.RecoveryCode); err != nil { /* ... */ } secureSessionID = user.SetSecureSessionID(u.ID) } // Passkey-only accounts fall through to here and receive a full session token: accessToken, err := user.GenerateJWT(u) ``` No branch requires a WebAuthn assertion during password login when `EnabledPasskey()` is true. The root cause is the mismatch between the **policy definition** (`Enabled2FA()` = OTP **or** passkey) and the **enforcement check** (`EnabledOTP()` only). The same `EnabledOTP()`-only gating in `RequireSecureSession()` (`internal/middleware/secure_session.go`) means passkey-only users are also exempted from step-up on sensitive actions. ## Proof of Concept Tested against nginx-ui built from source (`go build -tags unembed`) on `127.0.0.1:9000`, with WebAuthn configured and a victim account that has a registered passkey and **no** TOTP. The vulnerable code is identical on the production `main` branch (`api/user/auth.go` `Login` gates on `u.EnabledOTP()` only; verified at commit `6c86e5a`, 2026-05-17). Account state advertised by `GET /api/2fa_status`: ```json {"enabled":true,"otp_status":false,"passkey_status":true, ...} ``` Attacker logs in with **password only** (`POST /api/login`, encrypted params as the client normally sends): ``` HTTP 200 {"message":"ok","code":200,"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...."} ``` `code: 200` + a valid JWT = an authenticated session, with the passkey never used. For comparison, the identical account with a TOTP secret instead correctly returns the second-factor challenge: ``` HTTP 200 {"message":"The user has enabled 2FA","code":199} ``` | Account state | `POST /api/login` (password only) | |---|---| | Passkey registered, no TOTP | `code 200` + JWT — **2FA NOT enforced** | | TOTP registered | `code 199` — 2FA challenge enforced | This isolates the defect: the login path enforces OTP but ignores passkeys. ## Impact - Any account protected **only** by a passkey is reduced to password-only authentication. An attacker who obtains the password (phishing, reuse, leak) gains full access despite the registered security key. - In nginx-ui all authenticated users are effectively administrators and the terminal feature grants a host shell, so account takeover leads to full control of the managed nginx instance / host. - Users are given a false sense of security: the UI shows the account as 2FA-enabled while the second factor is not enforced at login. ## Remediation - Gate the second-factor decision on `u.Enabled2FA()` (not `u.EnabledOTP()`) in `Login`, in both SSO callbacks, and in `RequireSecureSession()`. - For a passkey-only user logging in with a password, return a "passkey assertion required" challenge and complete login only after a successful WebAuthn assertion (the `begin_passkey_login` / `finish_passkey_login` flow already exists and should be required as the second step). - Centralize session-token issuance so no login entry point can skip the 2FA decision. ## Affected components - `api/user/auth.go` — `Login` - `model/user.go` — `EnabledOTP`, `EnabledPasskey`, `Enabled2FA`, `AfterFind` - `api/user/2fa.go` — `get2FAStatus` - `internal/middleware/secure_session.go` — `RequireSecureSession` | CVE Database V5 | ||
| High | 8.8 | EPSS 0.3% | High8.8EPSS 0.3%CVE Database V5CVE-2026-107807 ## 1. Vulnerability Summary nginx-ui's `Node.Secret` is a master credential that bypasses all JWT/password authentication for the entire API. The application accepts this credential via a **URL query parameter** (`?node_secret=`), causing it to be recorded in plaintext in HTTP access logs, reverse proxy logs, browser history, and HTTP `Referer` headers. Additionally, the official cluster configuration format embeds node secrets directly into URL query strings stored in `app.ini` and environment variables, creating a systemic credential exposure pattern across the entire cluster deployment model. An attacker who gains read access to any log aggregation system, proxy log, or configuration file can extract the node secret and obtain full, persistent, unauthenticated administrative access to the nginx-ui API — including reading TLS private keys, modifying nginx configurations, and (when chained with Bug #1) achieving OS-level code execution. --- ## 2. Root Cause Analysis ### 2.1 Node Secret Accepted as URL Query Parameter The `getNodeSecret` function reads the credential from the URL query string as a fallback when the `X-Node-Secret` header is absent: [1](#3-0) This function is called in both `AuthRequired()` and `AuthRequiredWS()` middleware, meaning the query parameter bypass works for **all authenticated HTTP and WebSocket endpoints**: [2](#3-1) [3](#3-2) The same pattern is repeated in the WebSocket origin checker, which also reads `node_secret` from the URL: [4](#3-3) ### 2.2 Node Secret Is a Full Authentication Bypass The documentation explicitly states this is by design: [5](#3-4) When the secret matches, the middleware sets the request context to an admin-level init user and calls `c.Next()` — bypassing all JWT validation, session checks, and 2FA: [2](#3-1) ### 2.3 Cluster Configuration Embeds Node Secrets in URLs The official cluster configuration format, documented and used in `app.example.ini`, stores node secrets as URL query parameters: [6](#3-5) The `parseNodeUrl` function extracts the secret from the URL's query string and stores it in the database as the node's `Token` field: [7](#3-6) This means node secrets are embedded in: - `app.ini` on disk (readable by any process with filesystem access) - The `NGINX_UI_CLUSTER_NODE` environment variable (visible in `ps aux`, Docker inspect, Kubernetes pod specs, CI/CD logs) - The SQLite database `nodes` table as the `token` column in plaintext ### 2.4 Node Secret Generation Uses UUID The secret is auto-generated as a UUID v4 if not set: [8](#3-7) UUID v4 has 122 bits of entropy, which is adequate. However, the exposure surface described in this report makes entropy irrelevant — the secret is leaked through operational channels, not brute-forced. --- ## 3. Exposure Surface The following table maps each exposure vector to its source in the codebase: | Vector | How It Happens | Who Can See It | |---|---|---| | **HTTP access logs** | `GET /api/settings?node_secret=xxx` logged by nginx/caddy/apache | Log readers, SIEM operators | | **Application logs** | Gin debug mode logs full request URLs | Server operators, log aggregators | | **Browser history** | Admin uses `?node_secret=` URL directly | Anyone with browser access | | **HTTP Referer header** | Page with `?node_secret=` in URL links to external resource | Third-party servers | | **WebSocket URL logs** | `ws://host/api/ws?node_secret=xxx` logged by proxies | Proxy log readers | | **`app.ini` on disk** | Cluster node URLs contain `node_secret=` | Filesystem readers | | **Environment variables** | `NGINX_UI_CLUSTER_NODE=...&node_secret=...` | `ps aux`, Docker inspect, K8s pod specs | | **CI/CD pipeline logs** | Env vars printed during deployment | CI/CD log viewers | | **Database** | `nodes.token` column stored in plaintext SQLite | DB file readers | --- ## 4. Proof of Concept ### Scenario A: Log-Based Secret Extraction **Step 1 — Attacker gains read access to nginx access logs** (e.g., via a misconfigured log aggregator, a compromised monitoring account, or a separate vulnerability). **Step 2 — Search logs for the pattern:** ```bash grep -oP 'node_secret=[^&\s"]+' /var/log/nginx/access.log # Output: node_secret=a1b2c3d4-e5f6-7890-abcd-ef1234567890 ``` **Step 3 — Use the extracted secret for full API access:** ```http GET /api/settings HTTP/1.1 Host: target:9000 X-Node-Secret: a1b2c3d4-e5f6-7890-abcd-ef1234567890 ``` Response: Full settings JSON including `JwtSecret`, `NodeSecret`, all nginx paths, and all configured credentials. ```http GET /api/nginx/config?filepath=/etc/nginx/nginx.conf HTTP/1.1 Host: target:9000 X-Node-Secret: a1b2c3d4-e5f6-7890-abcd-ef1234567890 ``` Response: Full nginx configuration including any embedded credentials. ### Scenario B: Environment Variable Exposure in Docker/Kubernetes **Step 1 — Attacker reads a Kubernetes pod spec or Docker Compose file:** ```yaml environment: - NGINX_UI_CLUSTER_NODE=http://10.0.0.1:9000?name=node1&node_se | CVE Database V5 | ||
| Critical | 9.4 | EPSS 0.6% | CVE-2026-1078060xJacky nginx-ui · Code Injection Critical9.4EPSS 0.6%CVE Database V5CVE-2026-107806 A critical code injection vulnerability (CWE-94) exists in 0xJacky's nginx-ui versions from 2.3.8 up to but not including 2.5.0. An authenticated administrator with an active secure session can submit malicious backup key material and manifest to the restore API endpoint, which leads to replacement of the live configuration file including protected command settings. This allows execution of attacker-controlled commands in the Nginx UI runtime context, impacting confidentiality, integrity, and availability. The issue is fixed in version 2.5.0. | CVE Database V5 | ||
| High | 7.5 | EPSS 0.5% | CVE-2026-1078050xJacky nginx-ui · Uncontrolled Resource Consumption High7.5EPSS 0.5%CVE Database V5CVE-2026-107805 CVE-2026-107805 is a high-severity vulnerability in 0xJacky's nginx-ui versions from 2.5.0 up to but not including 2.6.0. It involves uncontrolled resource consumption due to temporary file staging of attacker-controlled request bodies before signature validation. This can lead to denial of service by exhausting filesystem and processing resources. The issue affects availability only and does not impact authentication, confidentiality, or integrity. The vulnerability is fixed in version 2.6.0. | CVE Database V5 | ||
| Medium | 5.3 | EPSS 0.2% | CVE-2026-1078040xJacky nginx-ui · Origin Validation Error Medium5.3EPSS 0.2%CVE Database V5CVE-2026-107804 ## Summary In Nginx UI versions 2.2.0 through 2.5.x, the official bundled reverse-proxy topology did not preserve the external client identity used by Gin. The backend treated the local proxy peer as the client because no trusted proxy was configured, while the proxy supplied the actual address in forwarding headers. ## Impact This has two distinct effects in bundled-proxy deployments: * **IP allowlist enforcement:** management API requests forwarded by the bundled proxy were identified as loopback and could pass the loopback exception even when the external source was not in the configured allowlist. Protected management operations still required valid credentials; this did not grant unauthenticated administrator access. * **Login availability:** failed login attempts from different external sources were attributed to one loopback address. An unauthenticated attacker could therefore trigger the shared temporary login-ban threshold and deny password or OTP login to other users behind the proxy until the ban expired. Existing authenticated sessions were not invalidated. ## Remediation Upgrade to Nginx UI 2.6.0 or later. The fix explicitly trusts only the intended bundled proxy, validates configured trusted proxies, uses the resolved client address consistently, and fails closed when an IP allowlist is enabled but the client address is invalid. Fix commit: https://github.com/0xJacky/nginx-ui/commit/e30e331303fc21cf077a2bea724bd79e66892eaf | CVE Database V5 | ||
| Medium | 6.3 | EPSS 0.5% | CVE-2026-107386rabbitmq amqp091-go · Unthrottled Resource Allocation Medium6.3EPSS 0.5%CVE Database V5CVE-2026-107386 amqp091-go is a Go AMQP 0.9.1 client. From 1.13.0 until 1.14.0, the frame-size mitigation from the prior allocation advisory can be bypassed before connection.tune completes because Connection.maxFrameSize uses zero for both the not-yet-negotiated and negotiated-unlimited states. A malicious or compromised AMQP peer can send a short body-frame header with a large declared payload length, causing ReadFrame and the body-frame parser to allocate attacker-selected memory before the payload is received or the frame's protocol state is rejected. The condition is reachable through public Open even when Config.FrameSize is set to the protocol minimum and can cause severe memory pressure, out-of-memory termination, or loss of the client process before authentication completes. This issue is fixed in version 1.14.0. | CVE Database V5 | ||
| Medium | 5.3 | Medium5.3GCVE Database A resource exhaustion vulnerability exists in Coraza v3 multipart body processor due to deferred file handle closures inside a loop. This causes file descriptors to accumulate until the request processing completes, potentially exhausting the file descriptor limit and causing denial of service. The issue affects all v3.x releases before 3.8.0. The vulnerability can trigger false positives in the Core Rule Set (CRS) and block legitimate multipart requests. A patch is available to fix the improper defer usage. | GCVE Database | |||
| Medium | 5.8 | Medium5.8GCVE Database Coraza v3 has a vulnerability where it fails to inspect URL-encoded form bodies if the Content-Type header includes media-type parameters such as charset=UTF-8. This causes Coraza to skip parsing the request body, allowing attackers to bypass custom rules inspecting POST arguments. The issue affects versions from 3.0.4 up to but not including 3.8.1. The vulnerability is rated medium severity with a CVSS score of 5.8. A patch is available to address this issue. | GCVE Database | |||
| Medium | 5.9 | Medium5.9GCVE Database Coraza v3 contains a vulnerability in its JSON response body processor where there is no recursion limit enforced when parsing JSON responses. This leads to unbounded recursion and CPU exhaustion when processing deeply nested JSON responses. The request path enforces a recursion limit, but the response path does not, causing quadratic CPU usage growth with nesting depth. This can result in significant CPU consumption and denial of service when ResponseBodyAccess is enabled and JSON responses contain deeply nested structures. | GCVE Database | |||
| Medium | 4.0 | Medium4.0GCVE Database Coraza v3 prior to 3.8.1 improperly handles multipart file upload filenames when the RFC 5987 extended filename* parameter uses a charset other than us-ascii or utf-8, such as iso-8859-1. This causes Coraza to ignore the filename* value and instead use the plain filename parameter or no filename, allowing attackers to bypass file extension or name-based detection rules. The vulnerability affects the FILES and FILES_SIZES variables and the file-vs-field routing, potentially letting malicious uploads evade inspection. The issue is fixed in version 3.8.1 by independently decoding filename* without charset restrictions and exposing both filename and filename* values. | GCVE Database | |||
| Medium | 4.0 | Medium4.0GCVE Database Coraza's cookie parser in versions prior to 3.8.1 does not fully strip ASCII control characters (CTLs) from cookie names and values, causing a mismatch between the WAF and backend application cookie parsing. This discrepancy can allow attackers to bypass WAF rules scoped to specific cookies by padding the Cookie header with CTLs adjacent to the '=' separator. The issue arises because Coraza trims only space and tab characters, whereas RFC 6265 requires trimming the full CTL range. A fix is available that aligns Coraza's parsing with RFC 6265 by trimming the full CTL range from cookie names and values. | GCVE Database | |||
| Medium | 4.0 | Medium4.0GCVE Database Coraza v3 before 3.8.0 has a vulnerability in its URI processing logic where malformed URIs containing raw control bytes cause the system to silently drop QUERY_STRING and ARGS_GET variables. This occurs because the URI parsing fails and the fallback logic to extract GET arguments is commented out, resulting in empty GET argument collections. The issue does not affect standard net/http integrations, which reject malformed URIs early, but affects integrations that call ProcessURI directly with unvalidated raw URIs, such as coraza-spoa and coraza-proxy-wasm. This can lead to bypass of OWASP CRS GET-side signature rules that rely on these variables. A fix is available. | GCVE Database | |||
| Medium | 5.8 | EPSS 0.3% | Medium5.8EPSS 0.3%GCVE DatabaseCVE-2026-104774 Coraza WAF versions 3.0.0 through 3.7.0 contain an off-by-one error in the jsDecode transformation when parsing JavaScript octal escape sequences. This flaw causes the WAF to incorrectly decode these sequences as null bytes, allowing attackers to bypass WAF rules that rely on this decoding. The vulnerability enables bypass of protections against attacks such as cross-site scripting (XSS) and SQL injection when payloads use octal escapes. The issue is fixed in version 3.8.0. | GCVE Database | ||
| High | 7.5 | High7.5GCVE Database A stack overflow vulnerability exists in the Coraza JSON body processor (github.com/corazawaf/coraza/v3) that can cause the entire host process to crash. This occurs due to an unbounded recursion in the gjson.Valid function when processing deeply nested JSON bodies that bypass argument and byte limits. An unauthenticated attacker can trigger this with a crafted JSON request body well within default and recommended size limits, causing a fatal stack overflow that terminates the process unconditionally. | GCVE Database | |||
| Medium | 5.8 | Medium5.8GCVE Database Coraza v3's JSON body processor flattens nested JSON properties into dot-separated keys without escaping dots in property names, causing key collisions. This allows an unauthenticated attacker to bypass OWASP Core Rule Set (CRS) inspection by overwriting malicious nested JSON values with harmless dotted keys. The vulnerability affects Coraza versions from 3.0.0 up to but not including 3.8.1. The issue was confirmed against CRS v4.25 and can bypass SQL injection detection rules. A patch is available for this vulnerability. | GCVE Database | |||
| High | 7.1 | EPSS 0.4% | High7.1EPSS 0.4%GCVE DatabaseCVE-2026-107223 ### Summary The `max` attribute of a `<col>` element in `xl/worksheets/sheetN.xml` is read verbatim on open with no check against `MaxColumns`, and `flatCols()` then walks `Min..Max` doing a `deepcopy.Copy` and `append` per iteration. Executed: `max="300000"`, only about 18x past the real 16384 limit, cost 46.2 s of CPU and 122 MB on a single `SetColWidth` call, and the growth is linear in `max` up to 2^31-1. Confirmed at `ae2113b` (HEAD at the time of audit). ### Details `col.go:547`, `flatCols()`, with the two loops at `:549` and `:564`: ```go for i := col.Min; i <= col.Max; i++ { ... for i := column.Min; i <= column.Max; i++ { ... fc = append(fc, deepcopy.Copy(...)) } ``` `column.Min` and `column.Max` are plain int attributes on `xmlWorksheet.go:279-280`, bound straight from the file. `MaxColumns` is 16384 (`templates.go:176`) and nothing in the parse path compares against it. The contrast that makes this an oversight rather than a design decision is inside the callers themselves. `SetColWidth` validates its own column argument through `parseColRange`, which clamps to `MaxColumns`. But `flatCols` iterates `ws.Cols.Col`, the file-loaded slice, so the caller's validated argument never constrains the loop. The crafted column expands no matter which column the caller touches. The row axis has the guard this axis is missing: GHSA-h69g-9hx6-f3v4 capped `checkSheet`'s row allocation at `TotalRows`, and GHSA-q5j5-6p94-4gwc capped streaming `Rows.Next`. There is no column-axis equivalent. Public entry points that flatten the existing columns: `SetColWidth` (`col.go:498` into `:534`), `SetColStyle` (`col.go:431` into `:477`), `SetColVisible` (`col.go:282` into `:313`), `SetColOutlineLevel` (`col.go:376` into `:407`). ### PoC Executed in-package: crafted a real xlsx, rezipped with an injected `<cols>` block before `<sheetData>`, opened it with `OpenReader`, then called `SetColWidth`. ```xml <cols><col min="1" max="2147483647" width="9"/></cols> ``` ```go f.SetColWidth("Sheet1", "A", "A", 12) ``` Measured: - `max="300000"`: 46.2 s CPU, 122 MB allocated, `ws.Cols.Col` grew to 300000 entries, from one call. - `max="5000000"`: did not complete in 110 s, killed by the test timeout. Growth is linear in `max`. At `max=2147483647` that is roughly two billion `xlsxCol` allocations, which is hundreds of gigabytes and in practice a permanent hang ending in OOM. ### Impact Any service that opens an untrusted spreadsheet and calls a column mutator. The input is a few dozen bytes of XML inside an otherwise ordinary workbook, no authentication is involved beyond whatever gates the upload, and the process is either wedged for minutes or killed by the OOM reaper. Availability only; no read or write primitive here. ### Suggested fix Validate `col.Min` and `col.Max` against `MinColumns`/`MaxColumns` when parsing the `<col>` element, or at the top of `flatCols`, returning `ErrColumnNumber` for out-of-range values. That mirrors what `checkRowNum` already does on the row axis. ### Why this is not GHSA-h69g-9hx6-f3v4 or GHSA-q5j5-6p94-4gwc Both of those are row-axis allocation bounds, and both fixes cap at `TotalRows`. Neither touched `<col>` parsing or `flatCols`. This is the same weakness class on the column axis, and it is arguably worse than the two that were fixed, because those had a cap that was bypassed while this one has no cap at all. | GCVE Database | ||
| Medium | 6.5 | EPSS 0.3% | CVE-2026-107225qax-os excelize · Improper Input Validation Medium6.5EPSS 0.3%CVE Database V5CVE-2026-107225 CVE-2026-107225 is an improper input validation vulnerability in the Go library excelize versions 2.8.0 through 2.11.0. The vulnerability arises because the GetStyle function's predicates only check upper bounds for style-table indices, allowing negative indices to be used. When a crafted styles.xml file contains negative fillId, borderId, or fontId values, these negative values bypass the upper-bound checks and cause negative slice indexing, leading to a panic during cell styling reads. No fix is currently available for this issue. | CVE Database V5 |
Page 8 of 37