kovidgoyal/kitty · error · ValueError

Incorrect permissions on pwfile: 0o{mode:03o}

Error message

Incorrect permissions on pwfile: 0o{mode:03o}

What it means

read_data_from_shared_memory() requires the ssh kitten's password shm file to have exactly mode 0600 (S_IREAD | S_IWRITE, i.e. owner-only read/write). stat.S_IMODE(shm.stats.st_mode) is compared to 0o600 and any other permission bits raise ValueError('Incorrect permissions on pwfile: 0o...'). This prevents other users on the machine reading the transmitted password.

Source

Thrown at kittens/ssh/utils.py:172

        shm.flush()
        atexit.register(shm.close)  # keeps shm alive till exit
        get_boss().atexit.shm_unlink(shm.name)
    return shm.name


def read_data_from_shared_memory(shm_name: str) -> Any:
    import json
    import stat

    from kitty.shm import SharedMemory

    with SharedMemory(shm_name, readonly=True) as shm:
        shm.unlink()
        if shm.stats.st_uid != os.geteuid() or shm.stats.st_gid != os.getegid():
            raise ValueError(f'Incorrect owner on pwfile: uid={shm.stats.st_uid} gid={shm.stats.st_gid}')
        mode = stat.S_IMODE(shm.stats.st_mode)
        if mode != stat.S_IREAD | stat.S_IWRITE:
            raise ValueError(f'Incorrect permissions on pwfile: 0o{mode:03o}')
        return json.loads(shm.read_data_with_size())


def get_ssh_data(msgb: memoryview, request_id: str) -> Iterator[bytes | memoryview]:
    # Unfortunately we cannot use EOF (\x04) to flush the kernel line buffer
    # because ssh with controlmasters mangles EOF replacing it with null bytes
    from base64 import standard_b64decode

    yield b'\nKITTY_DATA_START\n'  # to discard leading data
    try:
        msg = standard_b64decode(msgb).decode('utf-8')
        md = dict(x.split('=', 1) for x in msg.split(':'))
        pw = md['pw']
        pwfilename = md['pwfile']
        rq_id = md['id']
    except Exception:
        traceback.print_exc()
        yield b'invalid ssh data request message\n'

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Remove the offending file (`rm /dev/shm/kitty-ssh-*` style names) so kitty recreates it with mode 0600, then retry.
  2. Check your umask; start kitty with a normal umask (0022) so the shm file is created 0600.
  3. Do not chmod or copy pwfiles in /dev/shm; if you backed them up for debugging, delete them.
  4. If it persists, verify no other process is creating the file and report/check the kitty version for shm creation regressions.

Example fix

# before
ls -l /dev/shm/kitty*   # -rw-r--r--  -> ValueError: Incorrect permissions on pwfile: 0o644

# after
rm /dev/shm/kitty*
kitten ssh host          # file recreated with 0600
Defensive patterns

Strategy: validation

Validate before calling

import os, stat, glob

def clean_bad_mode_shm() -> None:
    for p in glob.glob('/dev/shm/kitty*'):
        try:
            mode = stat.S_IMODE(os.stat(p).st_mode)
            if mode != 0o600:
                os.unlink(p)
        except FileNotFoundError:
            pass

Try / catch

try:
    data = read_data_from_shared_memory(name)
except ValueError as e:
    if 'Incorrect permissions on pwfile' in str(e):
        remove_stale_pwfile(); retry_once()  # kitty recreates with 0600
    else:
        raise

Prevention

When it happens

Trigger: get_ssh_data() reads a pwfile in /dev/shm whose mode is not 0600 — e.g. created with a permissive umask, chmod'ed to 0644/0666 afterwards, restored from a backup with wrong modes, or written by a non-kitty process that uses default shm creation modes.

Common situations: A restrictive/permissive umask in the shell that launched kitty; another tool or script pre-creating or copying the shm file with different permissions; hardened or custom tmpfs mount options; debugging sessions where the file was touched manually.

Related errors


AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27). Data as JSON: /api/errors/5add1c6f3ce6d7ff. Report an issue: GitHub.