Skip to content

What measures prevent exposing plaintext LUKS passphrases in memory or logs during decryption and subprocess piping operations within the application? #2

@silverfisk

Description

@silverfisk

Analysis:

  • Subprocess Piping: The application correctly uses pipes for passing the plaintext passphrase to and from the gpg subprocess (via the input parameter and capture_output=True). This is a secure practice that avoids exposing the passphrase in the process list as a command-line argument.

  • Logging: The current implementation does not appear to have explicit logging that would write the passphrase to a log file. The use of --quiet also helps suppress unnecessary output.

  • Memory Exposure (Primary Weakness): The main risk lies in how the plaintext passphrase is handled in the application's memory.

    • In the FileKeyStore.get method, the decrypted passphrase from gpg is read into a bytes object (result.stdout) and then decoded into a Python str.
    • These objects reside in general-purpose process memory. There is no mechanism to securely wipe this memory after the passphrase is used. The data will remain in memory until the garbage collector reclaims it, and even then, the underlying memory is not zeroed out.
    • The operating system could swap the memory pages containing the passphrase to disk (e.g., to a swap file), creating a persistent, plaintext copy of the secret on the hard drive.

Recommendations:

  1. Minimize Plaintext Lifetime and Scope: The most effective mitigation is to avoid loading the plaintext passphrase into Python variables at all. The architecture should be refactored to pipe the output of the gpg --decrypt process directly into the stdin of the process that needs it (e.g., cryptsetup). This ensures the passphrase never resides in the luks-keeper application's memory space.

  2. Use Secure Memory Buffers: If direct piping is not feasible, the application must handle the passphrase in a secure buffer.

    • Read the passphrase into a mutable bytearray instead of an immutable str or bytes.
    • Use a library like python-memlock or ctypes to call the mlock() system call on the buffer. This prevents the operating system from swapping it to disk.
    • Explicitly zero out the bytearray (buffer[:] = b'\x00' * len(buffer)) as soon as it is no longer needed, ideally using a try...finally block or a context manager to guarantee cleanup.
  3. Guard Against Exception Leaks: While not an issue now, be cautious if adding future logging. A generic exception handler that logs the details of a subprocess.CalledProcessError could potentially leak the passphrase if it were ever present in the captured stdout or stderr attributes of the exception object.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions