The security invariant

Any field that reaches a shell is an execution surface until proven otherwise.

01 / The boundary

Container labels became command lines.

Arcane’s updater honored container lifecycle labels that were meant to describe hooks. Their values were run as commands rather than treated as descriptive metadata. Writing a label and triggering its execution were separate actions with different privileges, so the label content was an input that later reached a shell.

The upstream advisory records a command-execution issue via the pre-update and post-update lifecycle labels. The values were passed to a shell without sanitization or validation.

02 / Execution path

From a label value to /bin/sh -c inside the container.

The lifecycle helper looked up the label, trimmed it, and wrapped the value in a shell invocation. The updater then created a container exec with that command. A lower-privileged authenticated user could attach the labels to a project through the API; the command did not run then, but later, when an administrator initiated an update.

Execution occurred in the updated container with the update workflow’s context. How far it reached depended on that container’s mounts and configuration: sensitive host volumes or a privileged setup widened the blast radius, while a tightly scoped container contained it.

Who writes the label, who runs it
Before the fix
  1. Lower-privileged user

    Attaches lifecycle labels via the API.

  2. Administrator updates

    The hook runs during the update.

  3. Shell in the container

    The label value is executed.

After the fix
  1. No lifecycle hooks

    The label-driven execution path is removed.

  2. Update without hooks

    The updater no longer runs label commands.

  3. No execution surface

    There is no label value to run.

Conceptual control flow reconstructed from the upstream source. It is not a captured request or a TraceMint execution trace.

03 / Source & fix

Remove the hooks rather than sanitize shell input.

The upstream fix removes the lifecycle-hook feature: the label helper, the lifecycle execution code and their tests are deleted. Rather than attempt to make arbitrary shell input safe, the change eliminates the surface that ran it. The excerpts below show the pre-fix code where the label value became a shell command.

Deleting the feature is a deliberate trade-off: the hooks are gone, and with them the execution path. The corrective commit records the full removal.

Before · attacker-writable labelsSource
LabelPreUpdate  = "com.getarcaneapp.arcane.lifecycle.pre-update"  // Command to run before stopping containerLabelPostUpdate = "com.getarcaneapp.arcane.lifecycle.post-update" // Command to run after starting new container
backend/internal/utils/arcaneupdater/labels.gof86c1cfa
Before · label value to /bin/sh -cSource
return []string{"/bin/sh", "-c", v}
backend/internal/utils/arcaneupdater/labels.gof86c1cfa
Before · executed as a container execSource
execConfig := container.ExecOptions{	Cmd:          cmd,
backend/internal/utils/arcaneupdater/lifecycle.gof86c1cfa

Selected upstream lines; indentation normalized. Links include surrounding code at immutable revisions.

04 / Impact & conditions

Execution in the updated container, rated Critical.

The upstream advisory rates the issue Critical. The disclosed capability is command execution in the updated container when an administrator triggers an update on a project whose labels a lower-privileged user controlled. Access to host data depended on the container’s mounts and the deployment configuration.

A lower-privileged author
An authenticated user attaches the lifecycle labels via the API.
An administrator trigger
The command runs when an update is initiated.
A mount-dependent blast radius
Sensitive host volumes widen what the execution can reach.
05 / Review & regression

Confirm the label no longer produces a command.

A regression check attaches lifecycle labels to a container and initiates an update, confirming that no command derived from the label runs. On a patched build the feature is absent, so there is no command to execute. Review any remaining label handling for values that reach a shell. The scenarios below are suggested review checks, not reported TraceMint test results.

Suggested regression checks
ScenarioExpected boundary
Update without lifecycle labelsThe update proceeds normally.
Update with pre-update and post-update labelsNo command derived from the label values runs.
Lower-privileged author, admin triggerThe removed hooks provide no execution surface.
Other label handlingNo remaining label value is passed to a shell.
06 / Lessons & limits

Separate who writes input from who executes it.

For reviewers, trace who can write a field as well as who triggers its use. A privileged workflow can consume input created by a less-privileged account, and any value that reaches a shell is an execution surface. Removing a feature is a legitimate fix when the surface cannot be made safe.

The public advisory credits the TraceMint account as reporter, and the maintainers supplied the remediation. This study analyzes the public advisory and immutable source revisions; it does not claim sole discovery or access to any deployment.

Source record

Follow the evidence.

Public upstream records and immutable code revisions, reviewed 2026-09-22.

  1. Arcane security advisory

    Impact, prerequisites, severity and reporter credit.

  2. Label helper before the fix

    Immutable parent revision · f86c1cfa · label value wrapped in /bin/sh -c.

  3. Lifecycle execution before the fix

    The command runs as a container exec.

  4. Upstream corrective commit

    5a9c2f92 · remove the updater lifecycle hooks (#1468).

Brief code excerpts from getarcaneapp/arcane. Upstream license: BSD 3-Clause. All remediation described here is upstream work.

Read the original record

This case study analyzes an already-public advisory and upstream source. For the complete impact, remediation and credit record, see the Arcane security advisory.

Editorial publication is separate from disclosure. No private discovery timeline or method has been inferred.

More credited contributions