Skip to content
ghostshell
Loading Ghost Shell

terminal session audit for linux

Every shell session. Recorded. Encrypted. Replayable.

Ghost Shell is a terminal session recorder and root audit daemon. It records every shell session on your Linux hosts — including SSH — encrypts it at rest with AES-256-GCM, and lets root replay, search, and live-tail from a root-only store.

deb · rpm · static binary · source — install in under a minute ↓
$ ghostshell rec
ghostshell: recording to ghostshell-daemon (central) — type 'exit' or Ctrl-D to stop
$ sudo systemctl restart nginx
$ exit

$ sudo ghostshell play 20260711T142031-4471
 > 00:04 / 00:12 [###       ]  33%  1x   spc play  q quit

$ sudo strings /var/lib/ghostshell/alice/20260711T142031-4471.cast | head -1
TTEC2    # AES-256-GCM ciphertext — not alice's commands

Recorded as alice types it. On disk: root-owned ciphertext.

the problem

Your current audit trail is a polite fiction.

Three tools people actually use to answer “what happened?” — and where each one stops.

~/.bash_history

It lies.

  • User-writable — one history -c and it's gone
  • Drops pipes
  • Never records output — you see the command, never what it printed

script(1)

Plaintext, readable in practice.

  • Anyone who can read the typescript file reads every keystroke and secret it captured
  • No encryption, no central store, no access control
  • No way to search last month's typescripts across a host

asciinema

Built for demos, not audit.

  • Great for sharing a terminal clip
  • No central store, no encryption, no per-host retention story
  • Nothing ties a cast to a user on your box

Ghost Shell exists for the case where you actually need to answer “what happened on that box?”

root@web-01: ~
$ sudo ghostshell search --from "2 days ago" nginx
user=alice when=2026-07-11 14:20:31 session=20260711T142031-4471
cmd: -bash
> sudo systemctl restart nginx
> Job for nginx.service failed because the control process
exited with error code.

see it run

Record it. Replay it. Exactly as it happened.

A scripted tour of one session's life — or take over and drive the player yourself.

alice@web-01: ~

Users just work. The session records itself — to the central store when the daemon is up, to ~/.local/share/ghostshell when it isn't.

capabilities

Built for the 2 a.m. question.

Everything below ships in the one binary — no plugins, no server product.

  • Full-screen replay

    Seek, pause, 1/64×–64× speed, jump-to-command, click-to-seek. Original timing preserved; TUI apps like vim and htop redraw exactly.

    $ ghostshell play 20260711T142031-4471

  • Search everything

    Grep across every recording on the host, with natural-language date filters and per-user scoping.

    $ sudo ghostshell search --from "2 days ago" nginx

  • Live tail

    Stream an in-progress session as it happens — or print the last N lines of any finished one.

    $ sudo ghostshell tail -f <id>

  • Process tree

    Which command ran which, with exit codes and durations, captured by a bash trace shim.

    $ sudo ghostshell tree <id>

  • Local AI analysis

    A deterministic pass — failures, retry loops, slowest steps — plus an optional Ollama summary. Loopback-only unless --allow-remote.

    $ sudo ghostshell analyze <id>

  • Ansible run tracking

    Playbook runs recorded on the controller: plays, tasks, per-host status, output.

    $ sudo ghostshell ansible list

  • Auto-record on login

    An optional profile.d hook records every interactive login. Skips nested sudo su -. Fail-open.

    /etc/profile.d/ghostshell-autorec.sh

  • Export to plain asciinema

    Decrypt a recording to a standard v2 cast that plays with asciinema play.

    $ sudo ghostshell export -o session.cast <id>

Also in the box: bash tab-completion · ghostshell --check config validation · interactive prune retention · backup of the central store · optional playback password.

architecture

One binary, one daemon, one root-only directory.

The full path of a keystroke, from PTY to encrypted cast.

The live architecture diagram is desktop-only.

Open this page on a bigger screen to watch a session travel from PTY capture to the encrypted root-only store.

security model

Read this before relying on it.

What Ghost Shell guarantees, how the key works, and the one thing it is not.

The trust boundary

  • Central store /var/lib/ghostshell is root:root 0700; recordings 0600. Only root reads recordings — users can't read even their own.
  • The socket is 0666 so any user can submit a session — but the daemon attributes it to the kernel-reported UID via SO_PEERCRED. Identity can't be forged, and nothing can be read back over the socket.
  • Every read command — play, tail, tree, search, export, ls --all — requires root.
  • An optional playback password (hashed, root:root 0600) gates every content-revealing command — a second factor on top of root, not a replacement.
  • Ingest rejects symlinks and irregular entries — a crafted home directory can't redirect the root ingest.

Encryption and the key

  • Recordings are AES-256-GCM encrypted before they touch disk. On disk a .cast opens with the magic prefix TTEC1; the rest is ciphertext.
  • The key /var/lib/ghostshell/.ghostshell.key (root:root 0600) is unique per server and set immutable with chattr +i — rm, vi, sed, >, and tee fail, even as root, until someone runs chattr -i.
  • Back up the key. Lose it and every recording is permanently unreadable; the daemon refuses to start if the key is missing while encrypted recordings exist.

Filesystem caveat: ext4 and xfs honor +i; overlayfs, tmpfs and many network mounts silently ignore it. The daemon reads the flag back and logs:

WARNING: … the at-rest key is NOT protected from deletion/modification

Hardening, in passing

  • NoNewPrivileges
  • ProtectSystem=full
  • SystemCallFilter=@system-service
  • RestrictAddressFamilies=AF_UNIX
  • UMask=0077
  • race-tested
  • staticcheck + golangci-lint clean
  • systemd-analyze security: 3.9 OK
  • security-audited — AUDIT.md

install

On the box in under a minute.

Every vX.Y.Z tag publishes a .deb, an .rpm, and static binaries — plus SHA256SUMS.

install — debian / ubuntu
VER=$(curl -fsSL https://api.github.com/repos/Karannnnn614/Ghost-Shell/releases/latest | grep -oP '"tag_name":\s*"v\K[^"]+')
curl -fLO "https://github.com/Karannnnn614/Ghost-Shell/releases/download/v${VER}/ghostshell_${VER}_amd64.deb"
sudo apt install "./ghostshell_${VER}_amd64.deb"

Fetches the latest release; releases are published on every vX.Y.Z tag.

Packages create /var/lib/ghostshell (root-only), write /etc/ghostshell/ghostshell.conf with all defaults visible, and enable ghostshell-daemon.

the cli

Five commands you'll actually run.

All audit commands read the root-only store, so all of them require root.

Full reference: 10 personal + 12 audit commands. /docs/commands

positioning

The right tool depends on the question you're asking.

script(1) and asciinema answer “what did I do?”; auditd answers “what did the kernel see?”; Ghost Shell answers “what happened on that box — show me.”

Ghost Shell compared with script, asciinema, and auditd across nine capabilities
CapabilityGhost Shellscript(1)asciinemaauditd
Captures full terminal outputyesyesyesno — syscalls and execs, not terminal output
Encrypted at restAES-256-GCMplaintextplaintextplaintext logs
Central root-only store/var/lib/ghostshell, 0700no — file in user's cwdno — local files or upload/var/log/audit (root)
Replay with original timingyes — seek, 1/64×–64×, click-to-seekwith scriptreplayyesno replay
Live tail of a sessionyes — tail -f <id>nonoevents, not the terminal
Search across sessionsyes — with date filtersnonoausearch (event fields)
Per-command exit codes & timingyes — tree (bash shim)nonoyes (execve records)
Survives a user who avoids the wrapperno — fail-open, by design (see security model)nonoyes — kernel-level
Designed forhost audit + replayquick local capturedemos & sharingkernel/syscall audit

auditd records syscalls and events, not terminal output. It answers “what syscalls ran” — not “what did the operator see on screen.”

Does Ghost Shell replace auditd? No — they answer different questions. Run both.

faq

The questions a security review will ask.

Something missing? Open an issue

Know what actually happened on your box.

One static binary. Root-only store. Encrypted at rest. Fail-open.

$ sudo apt install "./ghostshell_${VER}_amd64.deb"

full commands ↑ install