PHP2Shell: Read our blog on the critical RCE vulnerabilities affecting 70% of the Internet
Vulnerability DatabaseGHSA-hxgj-4rj9-79fq

GHSA-hxgj-4rj9-79fq: 
Rust vulnerability analysis and mitigation

Severity (suggested): High (CVSS 3.1 ~8.8, AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N) CWE: CWE-269 (Improper Privilege Management), CWE-22 (unrestricted server-side path for projects) Affected: koreograf < 0.1.0-alpha.3 (0.1.0-alpha.1 and 0.1.0-alpha.2). Patched in 0.1.0-alpha.3.

Context

The README (line 227) says an operator "launches jobs and edits those objects" and that only an owner "manages credentials". LDAP group memberships default to role operator (README line 123). But:

  1. Templates without an execution environment always run locally (README line 83). auto also falls back to local execution when no container runtime is reachable, which is the default Compose and Helm setup. The local runner starts the job as the server process user (root in the shipped image), with full access to KOREOGRAF_DATA.
  2. An operator can create a shell template with an inline script (spec.script, src/runner.rs:537-545).
  3. An operator can create a project with source_type: "path" pointing at any directory on the server (src/http/catalog.rs:354-359 only checks is_dir()), for example /var/lib/koreograf. An operator in any team can therefore read secret.key and koreograf.db, plus the job directories from GHSA-8p3x-23rw-vfhv. That lets them decrypt the credentials of every team and organization and the saved LDAP and proxy passwords. In the shipped image this also means root code execution in the container.

Location

  • src/http/work.rs:128 – create_template requires only Role::Operator
  • src/http/work.rs:177 – launch_template requires only Role::Operator
  • src/http/catalog.rs:331 – create_project requires only Role::Operator
  • src/http/catalog.rs:354-359 – path projects accept any existing directory
  • src/runner.rs:1093-1103 – materialize_project uses the path as-is
  • src/runner.rs:537-545 – inline shell script
  • src/runner.rs:700-702 – local process spawn in the work dir, same uid as the server
  • Dockerfile:40 – server runs as root

Remediation (acceptance criteria)

  • source_type: "path" projects can only be created or changed by administrators, or only below configured base directories (for example KOREOGRAF_PROJECT_ROOTS, default empty = disabled for non-admins). The path is canonicalized and KOREOGRAF_DATA, /, /etc and the like are rejected.
  • Local execution for non-admin users is opt-in (for example KOREOGRAF_LOCAL_RUNNER_FOR=admins|all, default admins). Otherwise, local jobs run under a separate unprivileged uid that cannot read KOREOGRAF_DATA except its own work dir.
  • In Docker mode, the data dir is never mounted into job containers, only the job's own work dir (verify; this already looks correct at src/runner.rs:1357).
  • README "Users and permissions" and "Security" state precisely what an operator can do on the server.
  • The advisory recommends rotating secret.key-protected credentials if untrusted operators existed.

Testing notes

  • API test: as a non-admin operator, POST /api/projects with source_type: "path", source: "/" (and the data dir) returns 403 or 400. As an admin, an allowed root succeeds.
  • API test: as an operator with the default config, launching a local shell template is rejected (or, with the uid-separation approach, a script cat "$KOREOGRAF_DATA/secret.key" fails with permission denied).
  • Regression: the demo workflow (seeded by an admin) still runs with the default configuration.

Additional findings

Local runner jobs inherit the full server environment

Severity: High (adds to the existing High). CWE: CWE-526, CWE-269. Description. In local mode the job is spawned with Command::new("sh")...envs(env) and without env_clear(), so the child inherits the server's whole process environment. That environment typically contains KOREOGRAF_LDAP_BIND_PASSWORD, KOREOGRAF_ADMIN_PASSWORD and, if set, KOREOGRAF_SECRET_KEY (all set by Compose and the Helm chart). Any operator-run shell template or connection: local play can read them (for example env). This is a second, independent path to the same impact as GHSA-hxgj: the secrets leak even if file permissions on the data dir were later fixed. The README already says the container runner gets a cleaned environment (README:149); the local runner does not. Affected code.

  • src/runner.rs:700-705 – local spawn, .envs(env) without env_clear()
  • src/runner.rs:754-776 – base_env only adds variables
  • docker-compose.yml:9-27, Helm deployment template – secrets passed as env
  • Dockerfile:40 – root Remediation (add to GHSA-hxgj).
  • Call env_clear() on the local job command and pass only an allowlist (PATH, LANG, HOME, job KOREOGRAF_* variables, proxy variables, credential-injected variables).
  • Prefer reading secrets from files (*_FILE) and removing sensitive variables from the process environment after startup.
  • Test: a local shell job that runs env must not show KOREOGRAF_LDAP_BIND_PASSWORD, KOREOGRAF_ADMIN_PASSWORD or KOREOGRAF_SECRET_KEY.

Path projects and file:// git without allowlist

Severity: High (already covered). CWE: CWE-22, CWE-552. New details for the existing advisory.

  • file:// git URLs are accepted (src/runner.rs:1125-1135, valid_git) and every git call sets -c protocol.file.allow=always (src/runner.rs:1146-1150). Any local repository on the server can be cloned into a project, which gives the same effect as path projects.
  • GET /api/projects/{id}/contents scans the project directory with only Role::Viewer (src/http/sources.rs:85-97, project_dir at :353-356). A path project created by an operator is then enumerated for viewers too.
  • Positive (keep): the entry path is checked by check_relative (src/runner.rs:365-375), copy_tree skips symlinks, and inventory files are canonicalized and prefix-checked (src/http/sources.rs:373-379). Remediation (add). Allow file:// only for admins or under the same project-root allowlist as path, and drop protocol.file.allow=always otherwise. Canonicalize and prefix-check path projects at create, update and run time (TOCTOU, symlinked roots).

Extra vars exported as environment variables can override runner variables

Severity: Medium (defense in depth; requires operator). CWE: CWE-454. Description. export_plain_vars exports every string extra var with an identifier-like key into the job environment, after the KOREOGRAF_* variables are set. Because the last value wins, an operator can set KOREOGRAF_ENTRYPOINT (bypassing check_relative), KOREOGRAF_INVENTORY, KOREOGRAF_VAULT_LIST, PATH, LD_PRELOAD, ANSIBLE_*, BASH_ENV and so on. Webhook event keys are fixed names (alertname, status, instance, summary), but hook-level extra_vars and workflow node overrides are operator-controlled. This also matters in container mode. Affected code. src/runner.rs:656 (call), src/runner.rs:825-838 (export_plain_vars). Remediation. Deny keys with the prefixes KOREOGRAF_, ANSIBLE_, LD_, PYTHON, GIT_, TF_ and the names PATH, HOME, ENV, BASH_ENV, SHELL, IFS, or switch to an explicit opt-in list per template. Push the runner's own variables after the user variables so they always win. Add a unit test showing that KOREOGRAF_ENTRYPOINT in extra vars does not change the executed entry path.

Patches

Fixed in v0.1.0-alpha.3. KOREOGRAF_LOCAL_RUNNER_FOR defaults to admins: a job on the controller needs an administrator as launcher, and the template, project, inventory, and (for workflow runs) the workflow including node overrides must have been last saved by an administrator. Relaunch checks the stored parameters. Path projects and file:// Git URLs must resolve, at save time and again at run time, under KOREOGRAF_PROJECT_ROOTS (the examples directory is always allowed); the data directory and system directories are refused for everyone. Local jobs no longer inherit the server environment, and runner variables win over extra variables. This is a breaking change; see the release notes.

Workarounds

Run only trusted users as operators, set KOREOGRAF_RUNNER=docker and give every template an execution environment, and do not mount the data directory into job containers.

Known limitation

When local runs are limited to administrators, a relaunch compares the stored command, project, inventory, and workflow with the current objects, but not the stored extra variables. If an administrator relaunches a failed job that an operator started and that job falls back to the local runner, it runs with the operator's extra variables. Check the Parameters tab before relaunching such a job, or use KOREOGRAF_RUNNER=docker so that jobs with an execution environment never fall back to the controller.


Source: NVD

Related Rust vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-82vh-6gjg-8qcqMEDIUM6.8
  • Rust logoRust
  • koreograf
NoYesOct 23, 2026
CVE-2026-115567MEDIUM5.8
  • Rust logoRust
  • tokio
NoYesOct 23, 2026
GHSA-q752-5xf3-x24pHIGHN/A
  • Rust logoRust
  • koreograf
NoYesOct 23, 2026
GHSA-hxgj-4rj9-79fqHIGHN/A
  • Rust logoRust
  • koreograf
NoYesOct 23, 2026
GHSA-8p3x-23rw-vfhvMEDIUMN/A
  • Rust logoRust
  • koreograf
NoYesOct 23, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management