A flaw was found in yggdrasil-worker-package-manager. A local attacker with existing access to the system could exploit an argument injection vulnerability in the APT backend. This allows specially crafted package names, which begin with a hyphen, to be misinterpreted as command options by apt-get. Successful exploitation could lead to remote code execution (RCE) with root privileges, enabling the attacker to fully compromise the system's integrity, confidentiality, and availability.
AI_ONLY_REPORT
package: yggdrasil-worker-package-manager-0.2.3-4.el10
------
Summary: Remote Code Execution via APT Argument Injection:
attacker-controlled package names beginning with `-` are passed to
`apt-get` as raw arguments on Debian/Ubuntu code paths, allowing APT option
injection and potentially root code execution through dangerous APT
configuration directives for callers that can reach the worker dispatch
boundary.
Requirements to exploit: The attacker must be able to dispatch
package-manager requests to the worker over its configured D-Bus/dispatcher
trust boundary on a Debian/Ubuntu deployment where the APT backend is
selected. The `remove` path is directly reachable; the `install` path is
also reachable when the configured `allow-pattern` permits the supplied
name.
Component affected: `yggdrasil-worker-package-manager`, Debian/Ubuntu APT
backend in `package_manager_apt.go` (`PackageManagerApt.run`), reached from
message handling in `main.go` (`dataRx`)
Version affected: `yggdrasil-worker-package-manager-0.2.3-4.el10`, when
this code is built or deployed on Debian/Ubuntu systems using the APT
backend
Patch available: no released package fix established; proposed patch
included below
Version fixed: unknown
Upstream coordination: Not notified.
CVSS: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - 7.8 (HIGH)
AV:L - Exploitation requires access to the local D-Bus/dispatcher
boundary used to send requests to the worker.
AC:L - A leading-hyphen package name is sufficient to trigger APT option
parsing; no special race or environmental condition is required for the
injection primitive.
PR:L - The caller must already be allowed to dispatch requests to this
worker.
UI:N - No separate user interaction is required once the caller can
invoke the worker.
S:U - The impact is within the same system security scope.
C:H - Successful abuse of root-executed APT configuration can expose all
data available to the worker context.
I:H - Successful abuse can execute attacker-controlled actions as root
and fully compromise system integrity.
A:H - Successful abuse can disrupt package management or broader system
availability in the worker's root context.
Impact: Important. This issue can allow a caller that is authorized to use
the worker interface to cross a trust boundary and influence a
root-executed package-manager invocation, with high confidentiality,
integrity, and availability consequences if dangerous APT options are
accepted. It does not meet Critical because exploitation is not
unauthenticated remote and depends on a restricted dispatch boundary and
the Debian/Ubuntu APT code path.
Embargo: no
Reason: Exploitation depends on access to the configured worker
dispatch boundary and the Debian/Ubuntu APT backend rather than
unauthenticated remote reachability. The issue is serious, but the exposure
is constrained enough that coordinated public fixing without embargo
appears appropriate.
Acknowledgement: Aisle Research
Vulnerability Details: The APT backend invokes `apt-get` through
`exec.Command`, so this is not shell injection. The security flaw is
argument injection: untrusted `name` values are appended directly to the
`apt-get` argument list without an option terminator (`--`) and without
rejecting leading-hyphen values. As a result, a package name such as `-h`
or `-o...` is interpreted by APT as an option rather than a package name.
```go
func (p *PackageManagerApt) run(
command string,
args ...string,
) (stdout, stderr []byte, code int, err error) {
cmdargs := []string{"--assume-yes", command}
cmdargs = append(cmdargs, args...)
cmd := exec.Command("/usr/bin/apt-get", cmdargs...)
stdout, stderr, code, err = run(cmd, p.sendStdout, p.sendStderr)
return
}
```
The message handling path forwards `remove` requests without any
allow-pattern check, and `install` is only protected by the configured
allow-patterns. With the default permissive configuration, both paths
accept attacker-controlled names:
```go
case "install":
if !packageAllowed(m.Name) {
return fmt.Errorf("cannot install %v: does not match an allow pattern",
m.Name)
}
outb, errb, code, err = pm.Install(m.Name)
case "remove":
outb, errb, code, err = pm.Uninstall(m.Name)
```
```toml
allow-pattern = [".*"]
```
A deterministic proof of the bug is that `{"command":"remove","name":"-h"}`
causes APT help output instead of package removal behavior, showing that
the attacker-controlled `name` is parsed as an APT option. That establishes
the option-injection primitive. Escalation from this primitive to root
command execution depends on which APT configuration directives are
accepted for the chosen operation, so the exact RCE path is configuration-
and behavior-dependent, but the trust-boundary violation is directly
observable.
Steps to reproduce:
1. On a Debian/Ubuntu system with this worker installed, ensure the test
caller has access to the configured dispatch boundary for the
package-manager worker.
2. Dispatch a `remove` request with a leading-hyphen package name, for
example:
```json
{"command":"remove","name":"-h"}
```
3. Send it using the normal worker dispatch mechanism, for example:
```sh
echo '{"command":"remove","name":"-h"}' | yggctl dispatch --worker
package_manager -
```
4. Observe that the worker returns `apt-get` help output rather than
attempting to remove a package. This confirms the injected `name` was
interpreted as an APT option.
5. To test the broader impact, replace `-h` with a crafted `-o...` argument
and verify whether the selected APT directive is honored for the invoked
operation. The option-injection primitive is reproducible even where a
specific hook-style command execution path is not demonstrated.
Mitigation: Do not allow untrusted callers to access this worker's dispatch
boundary. On affected deployments, tighten `allow-pattern` values so
package names cannot begin with `-`, and avoid relying on the `remove` path
for untrusted input until validation is added. The APT backend should also
terminate option parsing with `--` before forwarding package names.
Proposed Fix: Reject empty or leading-hyphen package names before invoking
`apt-get`, and insert `--` so subsequent arguments are treated only as
package names. As additional hardening, consider applying the same
allow-pattern policy to `remove` that is already used for `install`.
```diff
diff --git a/package_manager_apt.go b/package_manager_apt.go
— a/package_manager_apt.go
+++ b/package_manager_apt.go
@@
func (p *PackageManagerApt) run(
command string,
args ...string,
) (stdout, stderr []byte, code int, err error) {
+ for _, a := range args {
+ if len(a) == 0 || a[0] == '-' {
+ return nil, nil, -1, fmt.Errorf("invalid package name: %q", a)
+ }
+ }
cmdargs := []string{"-assume-yes", command}
+ cmdargs := []string{"--assume-yes", command, "--"}
cmdargs = append(cmdargs, args...)
cmd := exec.Command("/usr/bin/apt-get", cmdargs...)
stdout, stderr, code, err = run(cmd, p.sendStdout, p.sendStderr)
return
}
```
------
This report was generated using AI technology. Always review AI-generated
content prior to use
AI_ONLY_REPORT package: yggdrasil-worker-package-manager-0.2.3-4.el10 ------ Summary: Remote Code Execution via APT Argument Injection: attacker-controlled package names beginning with `-` are passed to `apt-get` as raw arguments on Debian/Ubuntu code paths, allowing APT option injection and potentially root code execution through dangerous APT configuration directives for callers that can reach the worker dispatch boundary. Requirements to exploit: The attacker must be able to dispatch package-manager requests to the worker over its configured D-Bus/dispatcher trust boundary on a Debian/Ubuntu deployment where the APT backend is selected. The `remove` path is directly reachable; the `install` path is also reachable when the configured `allow-pattern` permits the supplied name. Component affected: `yggdrasil-worker-package-manager`, Debian/Ubuntu APT backend in `package_manager_apt.go` (`PackageManagerApt.run`), reached from message handling in `main.go` (`dataRx`) Version affected: `yggdrasil-worker-package-manager-0.2.3-4.el10`, when this code is built or deployed on Debian/Ubuntu systems using the APT backend Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Not notified. CVSS: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - 7.8 (HIGH) AV:L - Exploitation requires access to the local D-Bus/dispatcher boundary used to send requests to the worker. AC:L - A leading-hyphen package name is sufficient to trigger APT option parsing; no special race or environmental condition is required for the injection primitive. PR:L - The caller must already be allowed to dispatch requests to this worker. UI:N - No separate user interaction is required once the caller can invoke the worker. S:U - The impact is within the same system security scope. C:H - Successful abuse of root-executed APT configuration can expose all data available to the worker context. I:H - Successful abuse can execute attacker-controlled actions as root and fully compromise system integrity. A:H - Successful abuse can disrupt package management or broader system availability in the worker's root context. Impact: Important. This issue can allow a caller that is authorized to use the worker interface to cross a trust boundary and influence a root-executed package-manager invocation, with high confidentiality, integrity, and availability consequences if dangerous APT options are accepted. It does not meet Critical because exploitation is not unauthenticated remote and depends on a restricted dispatch boundary and the Debian/Ubuntu APT code path. Embargo: no Reason: Exploitation depends on access to the configured worker dispatch boundary and the Debian/Ubuntu APT backend rather than unauthenticated remote reachability. The issue is serious, but the exposure is constrained enough that coordinated public fixing without embargo appears appropriate. Acknowledgement: Aisle Research Vulnerability Details: The APT backend invokes `apt-get` through `exec.Command`, so this is not shell injection. The security flaw is argument injection: untrusted `name` values are appended directly to the `apt-get` argument list without an option terminator (`--`) and without rejecting leading-hyphen values. As a result, a package name such as `-h` or `-o...` is interpreted by APT as an option rather than a package name. ```go func (p *PackageManagerApt) run( command string, args ...string, ) (stdout, stderr []byte, code int, err error) { cmdargs := []string{"--assume-yes", command} cmdargs = append(cmdargs, args...) cmd := exec.Command("/usr/bin/apt-get", cmdargs...) stdout, stderr, code, err = run(cmd, p.sendStdout, p.sendStderr) return } ``` The message handling path forwards `remove` requests without any allow-pattern check, and `install` is only protected by the configured allow-patterns. With the default permissive configuration, both paths accept attacker-controlled names: ```go case "install": if !packageAllowed(m.Name) { return fmt.Errorf("cannot install %v: does not match an allow pattern", m.Name) } outb, errb, code, err = pm.Install(m.Name) case "remove": outb, errb, code, err = pm.Uninstall(m.Name) ``` ```toml allow-pattern = [".*"] ``` A deterministic proof of the bug is that `{"command":"remove","name":"-h"}` causes APT help output instead of package removal behavior, showing that the attacker-controlled `name` is parsed as an APT option. That establishes the option-injection primitive. Escalation from this primitive to root command execution depends on which APT configuration directives are accepted for the chosen operation, so the exact RCE path is configuration- and behavior-dependent, but the trust-boundary violation is directly observable. Steps to reproduce: 1. On a Debian/Ubuntu system with this worker installed, ensure the test caller has access to the configured dispatch boundary for the package-manager worker. 2. Dispatch a `remove` request with a leading-hyphen package name, for example: ```json {"command":"remove","name":"-h"} ``` 3. Send it using the normal worker dispatch mechanism, for example: ```sh echo '{"command":"remove","name":"-h"}' | yggctl dispatch --worker package_manager - ``` 4. Observe that the worker returns `apt-get` help output rather than attempting to remove a package. This confirms the injected `name` was interpreted as an APT option. 5. To test the broader impact, replace `-h` with a crafted `-o...` argument and verify whether the selected APT directive is honored for the invoked operation. The option-injection primitive is reproducible even where a specific hook-style command execution path is not demonstrated. Mitigation: Do not allow untrusted callers to access this worker's dispatch boundary. On affected deployments, tighten `allow-pattern` values so package names cannot begin with `-`, and avoid relying on the `remove` path for untrusted input until validation is added. The APT backend should also terminate option parsing with `--` before forwarding package names. Proposed Fix: Reject empty or leading-hyphen package names before invoking `apt-get`, and insert `--` so subsequent arguments are treated only as package names. As additional hardening, consider applying the same allow-pattern policy to `remove` that is already used for `install`. ```diff diff --git a/package_manager_apt.go b/package_manager_apt.go — a/package_manager_apt.go +++ b/package_manager_apt.go @@ func (p *PackageManagerApt) run( command string, args ...string, ) (stdout, stderr []byte, code int, err error) { + for _, a := range args { + if len(a) == 0 || a[0] == '-' { + return nil, nil, -1, fmt.Errorf("invalid package name: %q", a) + } + } cmdargs := []string{"-assume-yes", command} + cmdargs := []string{"--assume-yes", command, "--"} cmdargs = append(cmdargs, args...) cmd := exec.Command("/usr/bin/apt-get", cmdargs...) stdout, stderr, code, err = run(cmd, p.sendStdout, p.sendStderr) return } ``` ------ This report was generated using AI technology. Always review AI-generated content prior to use