locking sessions with ctrl+g, controlling who may attach, managing the cache directory and sockets, keeping secrets safe, and limiting dangerous plugins and pipes on production servers.

Episode 21 taught you to control Zellij anywhere — including inside Zellij. Episode 22 shifts perspective: it's no longer about convenience, but security. The Learn Zellij series is now in Phase 6, and ep22 specifically covers Security & Hardening Best Practice, to be followed by episode 23 (troubleshooting) and episode 24 (performance).
Why does security get its own topic? Because a terminal workspace is where the most valuable things on your machine live: database credentials, API tokens, SSH keys, and production commands. Zellij, with its client-server model and session sharing, expands the attack surface if not managed correctly. One accidental keystroke on a production server, one forgotten shared symlink, or one secret leaking into a layout file can lead to an incident far bigger than a messy terminal.
Episode 22 builds layered hardening: from Locked mode that stops accidental input, shared-session access control, socket and cache directory management, secret protection, restricting dangerous plugins and pipes, to best practices for running Zellij on a production server. You don't need to master everything at once — just start from the closest layer and build upward.
As a frame of mind, use the principle of least privilege: every component — session, plugin, pipe, user — should only have the minimum access needed for its job. A session that isn't shared, a plugin that isn't loaded, and a pipe that isn't attached are access that was never needed in the first place. Zellij security is essentially surface management: the smaller the exposed surface, the less there is to attack.
The Locked mode introduced in episode 21 turns out to be more than a nested-Zellij tool — it's a serious security feature. By pressing Ctrl+g, Zellij stops interpreting all input and passes it through verbatim to the pane. In a security context, this means preventing stray keystrokes from executing commands you didn't intend.
The most concrete scenario: you're working on a production server and have to leave your desk briefly. Instead of closing the session and losing work context, press Ctrl+g and go. Anything accidental — a slipping hand, a colleague playfully tapping the keyboard — will produce nothing while the LOCKED indicator glows in the status-bar.
Tip
Make Ctrl+g a reflex before leaving your desk, exactly like locking your laptop. In a terminal workspace full of dangerous commands — rm -rf, DROP TABLE, git push --force — one missed keystroke at the wrong second costs far more than the habit of pressing two keys.
Locked mode also protects against your own mistakes. When you're tired or waiting on a long process, this mode keeps you from typing anything into a pane running a critical command. It's the cheapest safeguard available in Zellij, and it should be the first habit you build.
Zellij's default security model is fairly strict: a session can only be accessed by the same user on the same machine. Sharing a session — as learned in episode 20 — isn't a feature that turns on by itself; you must make it explicit through the ~/.cache/zellij/shared/ directory with symlinks to session directories.
mkdir -p ~/.cache/zellij/shared
ln -s ~/.cache/zellij/dev ~/.cache/zellij/shared/dev
zellij attach devIts strength and its weakness are the same thing: sharing is a manual decision. Once a symlink is created, the session can be accessed from another device or by users you allow. Once you forget to remove it, that access stays open. So treat shared symlinks like door keys: create when needed, remove when done.
rm ~/.cache/zellij/shared/dev| Action | Security Effect |
|---|---|
| Create a symlink only during collaboration | Limits the access window |
| Remove the symlink when done | Closes access immediately |
Check ~/.cache/zellij/shared/ periodically | Detects sessions forgotten open |
| Never share a session holding secrets | Prevents credential exposure |
| Use separate Unix accounts per user | Clarifies the audit trail of who accessed what |
It's also important to understand the limits of revoking access. Removing a symlink doesn't stop the session itself — the session keeps living as long as its server runs; it just can no longer be attached from outside. If you want to fully stop access while also stopping the work inside, zellij kill-session is the right path. Understand this difference: remove the symlink to close the door, kill the session to shut down the room.
Warning
Never share a session running processes with secrets — for example a dev server storing tokens in its environment. Every participant in a shared session can read pane output, run commands, and even send input. If collaboration doesn't need full access, sharing output via pipes is better than sharing the session.
Zellij stores all session state in ~/.cache/zellij/. This directory contains session serialization data, shared symlinks, and log files. Because its contents are traces of your work, it's sensitive data — not a cache you can casually throw away.
| Location | Contents | Sensitivity Level |
|---|---|---|
~/.config/zellij/ | Configuration, layouts, themes | High — often version-controlled |
~/.cache/zellij/ | Session serialization, logs, shared | High — holds work state |
~/.cache/zellij/shared/ | Shared session symlinks | Critical — cross-machine access |
Over time, the cache directory can balloon and accumulate data from old sessions. Clean it periodically, but do it the right way: kill all sessions first, then delete. Deleting the cache while sessions are still running can corrupt state in use. Set a consistent cleanup rhythm — say every weekend or during deployment windows — so bloat never becomes a problem at the wrong time.
du -sh ~/.cache/zellij
zellij kill-server
rm -rf ~/.cache/zellijImportant
Lock the cache directory with tight permissions, for example chmod 700 ~/.cache/zellij. Serialization data stores pane information and executed commands — information other users on the same machine shouldn't be able to read. Loose default permissions are an often-overlooked gap.
Besides permissions, consider placing the cache on a separate location from the system partition if possible, so bloat doesn't threaten disk capacity used by other services. Most importantly: never store secrets as part of serialized state — that brings us to the next section.
The cause of secret leaks in Zellij is almost always the same: you put secret values in a file that should only contain instructions. KDL layouts are the most common example. Layouts support an env block for setting per-pane environments — very convenient, but layout files usually go into dotfiles repos that get committed and shared.
layout {
pane command="bash" {
env {
"API_KEY" "sk-very-secret"
}
}
}Once this file is committed, the secret spreads to git history, colleagues, and CI. The golden rule: configuration files contain names, not values. Secret values must come from a shell environment you set yourself, outside Zellij. With this pattern, the layout stays safe to commit while the secret lives only on the machines that genuinely need it.
export API_KEY="$(cat ~/.secrets/api_key)"
zellij| Don't | Instead |
|---|---|
| Tokens in KDL layouts | Environment variables from the shell |
Passwords in config.kdl | An external secret file with tight permissions |
| Secrets in committed layouts | Variables injected at runtime |
| Unlimited agent forwarding | ssh -A only to trusted hosts |
Warning
Remember that a pane is a real process: a pane's environment can be seen by other users on the same machine via ps. If you export a secret inside a shared session or on a multi-user machine, that secret isn't truly private. Minimize secrets flowing into panes, and limit the sessions holding them.
Zellij plugins are WASM code running with your user's privileges. The plugin API is limited, but a plugin can still send actions — including typing, switching tabs, even killing sessions. Pipes are even more open: zellij pipe can run actions directly against a session from outside. That means plugins and pipes are code-execution paths, not mere decoration.
The security principle is simple: only load code you trust. Load plugins from official sources or build your own, use pinned versions so they don't change silently, and audit suspicious plugins before putting them in a layout. In shared environments, restrict who can run zellij pipe — any shared-session participant who can invoke a pipe can send input to any pane.
If your workflow doesn't use pipes at all, don't install them in automation scripts. The smaller the exploitable surface, the smaller the risk you have to carry.
Finally, let's bring it all together into a policy that applies to production servers. A production server is the most valuable environment and the least tolerant of mistakes. The following policies keep Zellij a tool, not a gap.
PasswordAuthentication no on the server and use ed25519 keys.Ctrl+g before leaving the terminal; make it a habit for all production sessions.~/.cache/zellij/. Tight permissions and periodic cleanup as discussed above.Finally, build an audit habit: regularly check active sessions, leftover shared symlinks, and loaded plugins. Security is an ongoing process, not a one-time setup. A policy written today erodes over time if not maintained — so make this audit part of your operational routine, not a once-a-year event.
zellij list-sessionsThis simple routine audit is enough to detect suspicious sessions or processes you don't recognize. If you find a session you didn't create, kill it with zellij kill-session and investigate the cause before returning to work.
~/.cache/zellij/shared/ periodically and remove symlinks after collaboration ends.zellij kill-server first, then clean the cache directory.Ctrl+g a reflex before leaving your desk.Episode 22 built layered hardening for Zellij: Locked mode as the first line of defense against accidental input, shared-session access control through shared symlink management, socket and cache directory management with correct permissions and cleanup, secret protection so they don't leak into layouts or processes, restricting potentially dangerous plugins and pipes, and production server best practices from dedicated users to routine audits.
The points to take away:
Ctrl+g is the first and cheapest safeguard — make it a habit before leaving your desk.~/.cache/zellij/ is sensitive data: lock permissions and clean in the right order.Good Zellij security isn't about paranoia, but about consistent habits. In episode 23 next, we switch to the rescue act: Troubleshooting & Debugging — reading Zellij logs via RUST_LOG and ~/.cache/zellij/, diagnosing plugins that don't appear, wrong colors and TERM, keybinding conflicts, up to inspection with zellij action and minimal-layout reproduction. See you in episode 23, and may you not need to use it too often.