CVE-2026-73974: linuxfabrik-lib: Arbitrary root file read via live --test argument (lib.lftest) across sudoers-whitelisted plugins (LPE)

Published Aug 18, 2026
·
Updated

Summary Every Linuxfabrik check plugin that supports the shared --test argument (routed through lib.lftest.test()) will, when --test is supplied, treat the first CSV element as a filesystem path and read its full contents as the plugin's simulated STDOUT — running as root when the plugin is invoked through the shipped nagios/icinga sudoers allowlist. --test is a live production argument (centrally mapped to argparse.SUPPRESS, so it is hidden from --help but still accepted on the command line), not a build-time-only gate. This yields an arbitrary root file-read primitive (full disclosure on deb-updates; filtered disclosure / existence-and-readability oracle on ~22 other whitelisted plugins), i.e. local privilege escalation from the nagios account to root.

Root Cause - lib.lftest.test(args) (lftest.py lines 659-664): stdout = args[0]; if stdout and os.path.isfile(stdout): , stdout = disk.readfile(stdout). Element[1] (stderr channel) is read the same way. There is no path confinement on the supplied path. - check-plugins/deb-updates/deb-updates: --test is registered with type=lib.args.csv (lines 78-82). When supplied, control flows to stdout, , retc = lib.lftest.test(args.TEST) (line 143), bypassing the apt path (if args.TEST is None: at 121). Each returned line is stored as a package row and, under the default --query='1' (WHERE 1, matches all rows), every row is printed via '\n '.join([row['package'] ...]) → lib.base.oao(...). - The same --test/lib.lftest.test() mechanism exists identically on ~22 whitelisted plugins (e.g. docker-info), each performing a root open()/read of the attacker-named path. Disclosure degree varies by each plugin's downstream parser: full (deb-updates), filtered (docker-info echoes lines containing warning:/error:; openvpn-client-list echoes CLIENTLIST lines), or existence/readability oracle (JSON parsers).

Impact An attacker controlling the low-privilege nagios/icinga account (the documented threat model for the shipped sudoers file — same precondition as CVE-2026-52817) obtains the full contents of any root-readable file via deb-updates (e.g. /etc/shadow, /root/.ssh/id, TLS keys, cloud credentials), plus a fleet-wide root file existence/readability oracle and filtered content leak via the other plugins → local privilege escalation to root.

Proof of Concept Full disclosure (deb-updates): sudo /usr/lib64/nagios/plugins/deb-updates --test=/etc/shadow,,0 Filtered disclosure / oracle (docker-info, target routed to the stderr channel that gets echoed): sudo /usr/lib64/nagios/plugins/docker-info --test="dummy,/etc/shadow,0"

Attack Chain 1. Entry: sudo /usr/lib64/nagios/plugins/deb-updates --test=/etc/shadow,,0 - Action: the nagios user invokes the whitelisted plugin as root with a --test CSV whose element[0] is the target path and retc=0. - Guard: sudoers (Debian.sudoers:3) lists the binary only; --test is not gated to test builds. - Bypass proof: CONTRIBUTING.md documents --test as centrally mapped to argparse.SUPPRESS — hidden from --help but still accepted on the command line; lib.args.csv splits /etc/shadow,,0 into ['/etc/shadow','','0']. 2. Sink: lib.lftest.test(args.TEST) (deb-updates:143) reads element[0] as a file, as root. - Guard: none — no path confinement on element[0]. - Bypass proof (from lib source): lftest.py:661-664: stdout = args[0]; if stdout and os.path.isfile(stdout): , stdout = disk.readfile(stdout) — element[0], if it exists on disk, is opened and its contents returned as stdout. retc=0 (element[2]) so there is no early cu() abort. 3. Store + query: each line → lib.dbsqlite.insert(conn, {'package': item}, ...); default QUERY='1' → SELECT FROM debupdates WHERE 1. - Guard: --only-critical or a restrictive --query would filter, but both default to permissive (ONLYCRITICAL=False, QUERY='1'). - Bypass proof: attacker passes neither → all rows selected. 4. Disclosure: msg += '\n '.join([row['package'] for row in result]) → lib.base.oao(...) → stdout. - Guard: none. - Bypass proof: with len(result) > 0 the branch prints every row (every file line). 5. Impact: full contents of any root-readable file disclosed to the nagios user → root. On the ~22 other --test plugins the same primitive yields a filtered leak / universal root file existence-and-readability oracle.

Bypass Evidence - lib.lftest.test() file-read behavior verified directly from linuxfabrik-lib source (lftest.py:659-664, disk.readfile(stdout) when os.path.isfile(stdout)). - --test registration (type=lib.args.csv) and the stdout, , retc = lib.lftest.test(args.TEST) call verified on the latest release tag v6.0.0 at check-plugins/deb-updates/deb-updates:143 (GitHub contents API); default QUERY='1' confirmed. - No path-confinement guard exists on the --test path element in either the plugin or lib.lftest.

Affected Versions <= 6.0.0 (latest release; --test/lib.lftest.test() flow present on tag v6.0.0). Not covered by any existing advisory (none reference --test or arbitrary file read).

Suggested Fix Compile --test out of production builds (or gate it behind an explicit build/dev flag so it is not accepted at runtime), OR confine the --test path element(s) to a dedicated fixtures directory via realpath() + containment check before disk.readfile(). As defense-in-depth, constrain the sudoers entries to specific argument values so --test cannot be supplied to a root-run plugin.

--- Reported by zx (Jace)

Other sources

linuxfabrik-lib provides Python modules for database access, caching, shell execution, and API integrations, and Linuxfabrik Monitoring Plugins uses its shared testing helper across check plugins. Prior to linuxfabrik-lib 6.1.0 and Linuxfabrik Monitoring Plugins 7.0.0, lib.lftest.test() treated the first or second element of a --test CSV argument as a filesystem path and returned the file contents as simulated standard output or standard error without path confinement. The hidden but production-accessible --test argument was accepted by sudo-authorized plugins, so an attacker controlling the nagios or icinga account could use check-plugins/deb-updates/deb-updates with its default QUERY=1 to disclose every line of a root-readable file. Approximately 22 other plugins exposed filtered content or a root file existence and readability oracle through the same helper, while check-plugins/network-bonding/network-bonding and check-plugins/openstack-swift-stat/openstack-swift-stat had direct read paths that bypassed the helper. The library fix confines fixture reads to the invoking plugin's unit-test directory and refuses unsafe anchors, and the plugin fix routes the two bypasses through that helper. These issues are fixed in linuxfabrik-lib 6.1.0 and Linuxfabrik Monitoring Plugins 7.0.0.

MITRE

Affected Software

1 affected componentFixes available
pip/linuxfabrik-lib<6.1.0
6.1.0

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade pip/linuxfabrik-lib to a version that resolves this vulnerability.

    Fixed in 6.1.0
  2. Upgrade

    Upgrade linuxfabrik-lib to a version that resolves this vulnerability.

    Fixed in 6.1.0
  3. Upgrade

    Upgrade Linuxfabrik Monitoring Plugins to a version that resolves this vulnerability.

    Fixed in 7.0.0
  4. Configuration

    Constrain the sudoers entries to specific argument values so the hidden but production-accessible --test argument cannot be supplied to any root-run check plugin.

    sudoers allowlist for /usr/lib64/nagios/plugins/* --test argument acceptance = constrained (do not allow --test to be supplied to root-run plugins)
  5. Configuration

    In lib.lftest.test(), before calling disk.read_file() on the provided --test CSV element[0], constrain the path to a dedicated fixtures directory using realpath() + containment checks, rejecting unsafe anchors (removes arbitrary-path reads).

    lib.lftest.test() / --test CSV parsing fixture path confinement = confine --test element[0] to an allowed fixtures directory (realpath() + containment check) and refuse unsafe anchors
  6. Configuration

    Update each affected check plugin to route both stdout/stderr bypasses through the shared lib.lftest helper that enforces path confinement for --test.

    check plugins using shared --test helper (e.g., deb-updates) routing of --test bypass behavior = route bypass through the safe helper that enforces fixture-only reads

Event History

Aug 18, 2026
CVE Published
via MITRE·09:15 PM
Data Sourced
via MITRE·09:15 PM
DescriptionSeverityWeakness
Advisory Published
via GitHub·09:18 PM
Data Sourced
via GitHub·09:18 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Who is realistically exposed to this issue?

The practical exposure is to local users or processes running as the nagios account that can invoke affected plugins through the shipped nagios/icinga sudoers allowlist. The issue can disclose root-readable files through plugins that support the shared live --test argument.

2

What does an attacker need to exploit it?

An attacker needs local access as the nagios account and the ability to invoke a sudoers-whitelisted affected plugin with --test. No user interaction is required, and the supplied CSV value can cause the plugin to read a filesystem path without path confinement.

3

Is the vulnerable argument enabled in normal deployments?

The --test option is accepted in live production execution even though it is hidden from --help. It is not limited to build-time or test-only use.

4

How does impact differ between affected plugins?

The deb-updates plugin can disclose the full contents of a selected root-readable file. Approximately 22 other whitelisted plugins provide filtered disclosure or an oracle indicating whether a file exists and is readable.

5

What can be done if patching is not immediately possible?

Update to the release containing the referenced fix, v6.1.0. If updating is not immediately possible, restrict the nagios/icinga sudoers allowlist so the nagios account cannot invoke affected plugins with arbitrary arguments, particularly --test.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203