Skip to content

Harden log pager execution with LESSSECURE#197

Open
calh wants to merge 1 commit intogdraheim:masterfrom
calh:codex/fix-pager-escape-in-systemctl-log-command
Open

Harden log pager execution with LESSSECURE#197
calh wants to merge 1 commit intogdraheim:masterfrom
calh:codex/fix-pager-escape-in-systemctl-log-command

Conversation

@calh
Copy link

@calh calh commented Mar 13, 2026

Motivation

  • Playing around with the new Codex Security product, really fun stuff!
  • The log subcommand previously launched less with the inherited environment which allows shell escapes or external helper execution (via LESSOPEN/LESSCLOSE) and can lead to privilege escalation when run with elevated permissions.

Description

  • Update files/docker/systemctl3.py in SystemctlJournal.tail_log_file to set LESSSECURE=1 before invoking the pager.
  • Remove LESSOPEN and LESSCLOSE from the child environment to avoid executing external helper scripts.
  • Use os.spawnvpe/os.execvpe (instead of spawnvp/execvp) so the sanitized environment is applied when starting less.
  • Preserve existing behavior for --no-pager, --follow, and --lines code paths and only harden the interactive pager branch.

Testing

  • Ran python -m py_compile files/docker/systemctl3.py which succeeded.
  • Ran python files/docker/systemctl3.py --help which produced usage output successfully.

Criticality: high (attack path: high)
Status: new

Summary:
Introduced a new log subcommand that spawns less without secure mode, enabling a pager escape to root when the command is run with elevated privileges.
This commit adds a log subcommand that spawns external viewers for service logs. When no --no-pager is used, it invokes /usr/bin/less directly via os.spawnvp without setting LESSSECURE or otherwise disabling less’s shell escape features. If an unprivileged user is permitted to run systemctl log <unit> with elevated privileges (a common sudoers pattern for log viewing), they can drop into a root shell via less’s ! command or LESSOPEN/LESSCLOSE, resulting in privilege escalation. Mitigations include setting LESSSECURE=1, using a non-interactive viewer, or always forcing --no-pager when privileged.

Validation:
Rubric:

  • Identify pager constants and confirm LESS_CMD points to /usr/bin/less (files/docker/systemctl.py:165-167).
  • Confirm log subcommand ultimately calls log_unit_from for units (files/docker/systemctl.py:2152-2156).
  • Verify log_unit_from spawns less via os.spawnvp when not using --no-pager/lines/follow (files/docker/systemctl.py:2156-2173).
  • Confirm no LESSSECURE or equivalent pager hardening in codebase (grep for LESSSECURE returns none).
  • Demonstrate runtime debug output showing less invocation for systemctl log (artifacts/output.txt).

Attack-path analysis:
Final: high | Decider: model_decided | Matrix severity: medium | Policy adjusted: medium
Rationale: Kept high: the code path is in the core runtime and results in straightforward root shell access when systemctl log is delegated via sudo (a common operational pattern). While local-only and configuration-dependent, the impact is full privilege escalation with no in-code mitigation (no LESSSECURE).
Likelihood: medium - Exploitation is local-only and depends on a sudoers rule or equivalent privilege delegation for systemctl log; this is plausible but configuration-dependent.
Impact: high - If run with elevated privileges, less’s shell escape allows arbitrary commands as root, compromising container processes and filesystem.
Assumptions:

  • Non-root users may be granted sudoers access to run systemctl log <unit> for log viewing.
  • The image includes /usr/bin/less and pager use is not disabled (--no-pager not set).
  • The script is used in system mode (root) or via sudo, consistent with typical container/systemctl usage.
  • Local user can invoke systemctl log with elevated privileges (sudoers or equivalent)
  • Pager is enabled (no --no-pager)
  • /usr/bin/less is present
    Path:
    [user] -> [sudoers systemctl log] -> [systemctl3 log_unit_from] -> [less !] -> [root shell]
    Narrative:
    systemctl3.py defines LESS_CMD as /usr/bin/less and log_unit_from uses os.spawnvp to execute it whenever paging is enabled (lines 165–167 and 2156–2173). There is no code setting LESSSECURE or otherwise disabling less shell escapes. If a non-root user is allowed to run systemctl log with elevated privileges (a common sudoers pattern for log viewing), they can use less’s escape (! or LESSOPEN) to execute commands as root, resulting in local privilege escalation.
    Controls:
  • Requires privileged invocation (sudoers/system mode) to elevate impact
  • --no-pager disables the less invocation
  • No network exposure (local CLI only)
    Blindspots:
  • No runtime configuration or sudoers policies available to confirm how often systemctl log is delegated.
  • Static review cannot confirm whether deployments already set LESSSECURE or always use --no-pager.
  • No container runtime context to determine whether non-root users exist in typical images.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant