T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/office/soffice.py:28
- Finding
- Predictable LD_PRELOAD Artifact Enables Local Code Execution<![CDATA[ ## Vulnerability Details **File Location**: `scripts/office/soffice.py`, lines 28-64 **Vulnerability Type**: Unsafe temporary file handling and unverified dynamic-library injection **Risk Level**: High ### Vulnerable Code ```python def get_soffice_env() -> dict: env = os.environ.copy() env["SAL_USE_VCLPLUGIN"] = "svp" if _needs_shim(): shim = _ensure_shim() env["LD_PRELOAD"] = str(shim) return env def run_soffice(args: list[str], **kwargs) -> subprocess.CompletedProcess: env = get_soffice_env() return subprocess.run(["soffice"] + args, env=env, **kwargs) _SHIM_SO = Path(tempfile.gettempdir()) / "lo_socket_shim.so" def _needs_shim() -> bool: try: s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.close() return False except OSError: return True def _ensure_shim() -> Path: if _SHIM_SO.exists(): return _SHIM_SO src = Path(tempfile.gettempdir()) / "lo_socket_shim.c" src.write_text(_SHIM_SOURCE) subprocess.run( ["gcc", "-shared", "-fPIC", "-o", str(_SHIM_SO), str(src), "-ldl"], check=True, capture_output=True, ) src.unlink() return _SHIM_SO ``` ### Technical Analysis The native shim and its C source are placed at fixed, predictable names in the shared system temporary directory. If `lo_socket_shim.so` already exists, `_ensure_shim()` accepts it without verifying its ownership, permissions, file type, contents, or cryptographic integrity. When `_needs_shim()` detects that an AF_UNIX socket cannot be created, the unverified file is assigned to `LD_PRELOAD`. LibreOffice is then launched with that environment. The operating-system loader executes the constructors and intercepted functions in the supplied shared object before the normal application code. The source and output filenames are also susceptible to symlink and time-of-check/time-of-use attacks because they are written and compiled through sha ...[truncated 1506 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not reuse a fixed library from a shared temporary directory. 2. Create a private temporary directory using `tempfile.TemporaryDirectory()` and ensure it is accessible only to the current user, normally with mode `0700`. 3. Create source and output files with exclusive-creation semantics and reject symbolic links or non-regular files. 4. Compile the library into the private directory for each invocation, or package a reviewed binary whose cryptographic digest is verified before use. 5. Before setting `LD_PRELOAD`, verify the file's owner, permissions, type, canonical location, and expected digest. 6. Avoid inheriting unrelated preload variables from the parent environment. Construct a minimal subprocess environment and explicitly remove unexpected `LD_PRELOAD` or similar loader-control variables. 7. Prefer a LibreOffice configuration that does not require native function interception. If the shim remains necessary, isolate LibreOffice in a dedicated low-privilege sandbox with narrowly scoped filesystem access. 8. Add tests that pre-create files and symlinks at the old predictable paths and confirm that they are never loaded or overwritten. ]]>
