FlawOpen

flawopen.com/Teardowns/cve-2024-7646-ingress-nginx-annotation-code-injection

● CVE-2024-7646 · CVSS 8.8 · High
FlawOpen Security Research

CVE-2024-7646: Ingress-NGINX Validation Bypass

A carriage-return bypass enabled command injection and access to controller credentials. Fixed in 1.11.2/1.10.4; ingress-nginx is retired.

💡 Plain English Explainer (ELI5)

Imagine a gatekeeper that checks whether a form contains an allowed word but fails to check the whole value. A carriage return can change how the next system reads the remaining text. Here, an annotation passed a partial regex check and was later written into generated NGINX configuration. The fix validates the complete value and handles carriage returns safely.

Core Concepts & Subsystem Terms

Ingress object
A Kubernetes API resource that describes routing from an external host or path to a Service; users may have permission to create these without cluster-admin rights.
Annotation validation bypass
An annotation value passed a validator that matched only an allowed substring instead of requiring the complete value to be one of the permitted options.
Carriage return (`\r`)
A control character used as a line break in some formats. If validation and downstream configuration generation interpret it differently, it can change where configuration lines begin.
Controller service account
The Kubernetes identity used by the ingress-nginx controller. The upstream security notice says its default permissions can include access to all cluster Secrets.

Framework mappings

  • CWE reference for the weakness described in this guide: CWE-20

Root Cause Analysis

CVE-2024-7646 is an annotation-validation bypass in ingress-nginx, not the unrestricted use of a custom Lua snippet. The auth-tls-verify-client validator used a Go regular expression without start and end anchors, so MatchString could accept a value containing a valid option as only a substring. A carriage return in the annotation could then be interpreted differently while the controller cleaned generated NGINX configuration. The upstream fix tightens the option regex to match the entire value and updates cleanConf to handle bare carriage returns safely. The Kubernetes security notice says an actor who can create Ingress objects can bypass validation, inject commands, and obtain the controller credentials; in the default configuration those credentials can read all cluster Secrets. This is a high-severity, authenticated Kubernetes API path (CVSS 8.8), not an unauthenticated request from any network client. The project was retired in March 2026, so upgrading to a historical fix is only an immediate containment step; deployments should migrate to a maintained controller or Gateway API implementation.

Step-by-Step Attack Flow

Step 1

A user can create an Ingress

The attacker needs Kubernetes API permission to create an Ingress object. The issue is especially relevant in multi-tenant clusters where that permission is delegated to application teams.

Step 2

An annotation passes a partial match

The vulnerable auth-tls-verify-client regular expression lacked anchors. Go MatchString could therefore accept a longer value containing an allowed option, rather than requiring an exact permitted value.

Step 3

Carriage-return handling crosses the config boundary

The annotation is incorporated into generated NGINX configuration. The patch series fixes both whole-value validation and handling of bare carriage returns during config cleanup, closing the mismatched interpretation path.

Step 4

The controller identity is exposed

The Kubernetes security notice says successful command injection can obtain the ingress-nginx controller credentials. In the default configuration, that service account can access all cluster Secrets; the impact depends on the deployed RBAC permissions.

Source Code: Flaw vs. Secure Implementation

These are excerpts from the upstream fixes for CVE-2024-7646: PR #11719 anchors the allowed auth-tls-verify-client values, and PR #11721 handles bare carriage returns in cleanConf. The 1.10 branch received the corresponding #11718 and #11722 changes. The code shown omits unrelated surrounding function logic.

UNPATCHED FLAW
// internal/ingress/annotations/authtls/main.go (before)
authVerifyClientRegex = regexp.MustCompile(`on|off|optional|optional_no_ca`)

// internal/ingress/controller/template/template.go (before)
switch c {
case ' ', '\t':
    needOutput = lineStarted
case '\n':
    needOutput = !(!lineStarted && emptyLineWritten)
    nextLineStarted = false
}
HARDENED SECURE PATCH
// internal/ingress/annotations/authtls/main.go (fixed)
authVerifyClientRegex = regexp.MustCompile(`^(on|off|optional|optional_no_ca)$`)

// internal/ingress/controller/template/template.go (fixed)
switch c {
case '\r':
    rest := in.Bytes()
    if len(rest) > 0 && rest[0] != '\n' {
        c = ' '
        needOutput = lineStarted
    }
case '\n':
    needOutput = !(!lineStarted && emptyLineWritten)
    nextLineStarted = false
}

Engineering & System Hardening Checklist

Sources