# drduh/pwd.sh: Bash secrets management with GnuPG

> pwd.sh is a Bash script for storing and retrieving text secrets through GnuPG symmetric encryption. It suits Unix users who want a small command-line workflow, inspectable GnuPG files, timestamped revisions, and optional Pepper-based backup protection.

**drduh/pwd.sh** — Manage secrets with Bash and GnuPG symmetric encryption

- Repository: https://github.com/drduh/pwd.sh
- Website: https://drduh.github.io/pwd.sh/
- Stars: 1,563 · Forks: 134
- Language: Shell
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/drduh-pwd-sh

## What pwd.sh stores

pwd.sh addresses a specific problem: keeping text secrets, including passwords, in an encrypted local store that can be operated from a terminal. It is aimed at users who already work in a Unix shell environment and are comfortable with Bash, GnuPG, environment variables, and encrypted files. The repository describes pwd.sh as a Bash script, not as a hosted service or a separate database server.

The storage model has two parts. Each secret is written to a randomly named file in a storage directory. An encrypted index maps usernames to the files that contain their secrets. The README states that both the index and the secret files can be decrypted directly with GnuPG, without pwd.sh. That separation is useful for backup and inspection, but it also means the security of the store depends on the encrypted files and the passphrase used for GnuPG operations.

pwd.sh also retains revision information. A secret is associated with an epoch timestamp, and the most recent version is selected by default. The interface can list available names and paths, or request a particular revision using the username followed by an @ character and a timestamp. This is a useful alternative to replacing each secret in place when an older value may still be needed.

The project is not a general-purpose credential platform. The available operations cover writing, reading, listing, random secret and username generation, backup creation, version information, and help. The README does not document team sharing, access-control roles, automatic synchronization, browser integration, or an API. Its scope is therefore a local, single-user command-line workflow unless additional tooling is added around it.

## The encrypted index and timestamped files

The central design choice is to keep the index and secret contents as GnuPG-encrypted material rather than hiding them inside a proprietary store format. When a username is written, pwd.sh creates a randomly named secret file and records the relationship in the encrypted index. The README says that the index maps usernames to secrets contained in files. It also says that the files and index can be decrypted directly with GnuPG, which makes the storage format less dependent on the script itself.

Revision control is timestamp based. A newly written value receives an epoch timestamp, and a read operation defaults to the latest version. A specific version can be addressed by appending @1574723600 to the username in the documented example. The timestamp is part of the lookup syntax, so users who need to recover an earlier credential must know which revision they want or inspect the listing first.

The random filenames reduce the chance that a secret can be identified from its filename alone, while the index provides the mapping from a readable username. The index can also include an unencrypted comment through `PWDSH_COMMENT`. That setting is explicitly identified as unencrypted, so operators should not place sensitive values in it.

This architecture gives pwd.sh a useful boundary: the script can be replaced or bypassed for direct GnuPG access. The trade-off is that anyone who obtains the encrypted store still needs the correct GnuPG passphrase, and anyone who obtains both a valid passphrase and the store may be able to read the secrets. The repository does not document an additional authorization layer.

## Installing pwd.sh and creating a first secret

The README offers two installation routes. Clone the repository for the latest version, or download the script directly from the raw GitHub URL. The clone command installs the project files under the repository directory; the downloaded script is a single `pwd.sh` file that must be made usable for the current user according to the local shell environment.

To use the latest version from the repository, clone it with:

```bash
git clone https://github.com/drduh/pwd.sh
```

The README then directs users to run the script interactively with `./pwd.sh`, or to symlink it into a directory in `PATH`. To fetch only the script, use:

```bash
wget https://raw.githubusercontent.com/drduh/pwd.sh/main/pwd.sh
```

After obtaining the script, the first documented write operation creates a 20-character secret for `userName`:

```bash
./pwd.sh w userName 20
```

The value `20` is the requested secret length. The README does not provide a separate initialization command, passphrase prompt transcript, or expected output for this first write, so the operator should follow the GnuPG prompts presented by the script and verify that the store and index were created at the configured paths.

The interactive menu exposes the same operations as single-letter commands: `w` writes, `r` reads, `l` lists, `s` generates a random secret, `u` generates a random username, `b` archives materials, `v` prints version information, and `h` prints help. This makes a first use possible either through the menu or through command-line arguments.

## Reading, revising, and restoring pwd.sh data

Reading a secret uses the username as the selector:

```bash
./pwd.sh r userName
```

By default, this retrieves the most recent version. Listing the store provides the names and paths available for inspection:

```bash
./pwd.sh l
```

A specific revision is selected by adding the epoch timestamp to the username:

```bash
./pwd.sh r userName@1574723600
```

The timestamp syntax is concrete but requires the operator to preserve or recover the timestamp when an old value is needed. The README does not document a command for renaming, deleting, or merging secrets, so those operations should not be assumed.

Backups are created with:

```bash
./pwd.sh b
```

The resulting archive uses a configurable `PWDSH_BACKUP_NAME`. The documented default includes `v4-pwd.sh.hostname.2026-12-31.tar`, but operators should check the configured value before relying on a particular filename. The README gives the following extraction command for a restored archive:

```bash
tar xvf pwd*tar
```

This command extracts the archive contents into the current directory. It is not a documented verification or rollback procedure. The archive includes the encrypted materials, but the Pepper feature is explicitly not included in backup archives. Recovery therefore depends on having both the archive and the separately stored Pepper when Pepper is enabled.

## GnuPG, clipboard, and secret-generation settings

Configuration is handled through environment variables rather than a configuration file owned by pwd.sh. `PWDSH_STORE` controls the storage directory and defaults to `v4-pwd.sh.secret`. `PWDSH_INDEX` controls the index filename and defaults to `v4-pwd.sh.index`. These paths are important during restore, backup, and migration because pwd.sh must locate the same materials.

Secret output is controlled by `PWDSH_CLIP_OUT`, `PWDSH_CLIP_CMD`, and related settings. The default clipboard command is `xclip`, while macOS uses `pbcopy`. `PWDSH_CLIP_ARG` is disabled by default. Setting it to `-i -selection clipboard` selects the primary clipboard for xclip. `PWDSH_CLIP_SEC` controls how many seconds a secret remains in the clipboard or on screen, with a default of `10`. These options affect both convenience and exposure. The repository does not document behavior when the selected clipboard command is missing or fails, so users should verify clipboard support on their own system.

Generation is configurable too. `PWDSH_LEN` sets the default length to `20`, while `PWDSH_CHAR` defines the character set as `A-Za-z0-9!@#$%^&*()_+`. `PWDSH_COPY` can copy a secret to the clipboard before writing when set to `1` or `true`. `PWDSH_ECCHO` controls the character echoed during password input and defaults to `*`. These settings can make scripted use possible, but they also change the security properties of generated values and terminal input. The repository recommends GnuPG options in `config/gpg.conf`, without claiming a specific algorithm or configuration in this README.

## Pepper protection and its backup boundary

The optional Pepper feature adds a separate random string to the storage passphrase. When `PWDSH_PEPPER` points to a valid file, pwd.sh generates and displays the Pepper once, then saves it to that file. The README instructs users to record it in a secure, durable location and provides passphrase templates as examples. The feature is disabled unless explicitly enabled.

The stated purpose is to allow a more memorable, possibly weaker storage passphrase while still making backups harder to attack through passphrase brute force, provided the Pepper is backed up separately. That is a narrow backup-security property, not a replacement for a strong passphrase. The README does not specify the Pepper length, entropy, file permissions, generation algorithm, or exact passphrase construction beyond saying that it is appended.

The recovery boundary is severe and explicit. Pepper is not included in backup archives, and without the Pepper the secret storage is not accessible with the passphrase alone. A backup operator therefore has two separate recovery assets to manage: the encrypted archive and the Pepper file or recorded Pepper value. Losing the Pepper can make otherwise valid backups unusable. The feature is most appropriate for operators who understand that separation and can test the recovery path before relying on it.

## Maintenance, licensing, and practical limits

The repository is not archived, and the last push was on 2026-08-24. Recent releases include v4 on 2026-08-24, 3.0 on 2024-07-05, and 3.0b1 on 2024-03-24. The project is a Shell script with an MIT license. 

The upgrade path is not documented as an automated migration system. The versioned defaults for the store and index suggest that version-specific filenames are part of the layout, but the README does not explain how to migrate data between releases. Operators should inspect `v` output, compare release notes, and verify the expected `PWDSH_STORE` and `PWDSH_INDEX` paths before changing versions. The single-script repository layout keeps deployment simple, while upgrades still require attention to GnuPG compatibility and backup restoration.

A real limitation is the absence of documented team controls, centralized policy, hardware integration in the core script, and audit mechanisms. The README points to drduh/Purse and YubiKey as an integration for using a YubiKey instead of a passphrase, but that is a separate project and is not a feature of pwd.sh itself. For a single local user with text secrets, this narrow model may be sufficient. For shared credentials or operational access control, it is the wrong tool unless another system supplies those requirements.

## pwd.sh compared with a managed secrets service

The closest alternative described by the repository is not a competing password manager with the same feature set. The README points to drduh/Purse as a YubiKey integration, while the direct GnuPG model itself can be compared with manually storing encrypted GnuPG files and maintaining an index. A managed secrets service would normally centralize access and policy, but pwd.sh does not document such a service or claim parity with one.

The practical difference is control and scope. pwd.sh keeps encrypted material in files, exposes read and write commands through Bash, and allows direct GnuPG access without the script. That favors local control, shell workflows, and straightforward backup handling. It does not provide the documented collaboration and policy features expected from a service. Conversely, a service-based approach would add infrastructure and operator responsibilities that this repository does not describe.

The comparison should therefore focus on the desired operating model. Choose pwd.sh when encrypted local files, timestamped revisions, and direct GnuPG compatibility are the priorities. Keep looking elsewhere when centralized sharing, role-based access, browser integration, or a managed recovery process is required.

## Conclusion

Adopt pwd.sh if you want a small Bash-based secret store with GnuPG-compatible encrypted files, revision selection, and backup commands. Do not choose it as a replacement for a managed team vault or a hardware-backed setup without verifying GnuPG, clipboard behavior, Pepper storage, and backup procedures first. Its format is straightforward to inspect, but its security and recovery depend on the passphrase, optional Pepper file, and the machine holding the encrypted store.

## FAQ

### How do I install pwd.sh?

The README provides two documented options: clone the repository with `git clone https://github.com/drduh/pwd.sh`, or download the script with `wget https://raw.githubusercontent.com/drduh/pwd.sh/main/pwd.sh`. Run the script with `./pwd.sh` or symlink it into a directory in `PATH`.

### How do I create and read a secret with pwd.sh?

Use `./pwd.sh w userName 20` to create a 20-character secret for `userName`, then use `./pwd.sh r userName` to read the most recent version. The README also documents listing secrets with `./pwd.sh l` and selecting a revision with `./pwd.sh r userName@1574723600`.

### Does pwd.sh include the Pepper in its backup archive?

No. The README explicitly states that the Pepper is not included in backup archives and that the secret storage will not be accessible with the passphrase alone without it.

### Can GnuPG read pwd.sh files without pwd.sh?

Yes. The README states that both the encrypted index and secret files can be decrypted directly with GnuPG, without pwd.sh.

### How does pwd.sh generate random secrets?

The README documents the `s` command for generating a random secret and the `u` command for generating a random username. The default secret length is controlled by `PWDSH_LEN`, which is `20`, and the character set is controlled by `PWDSH_CHAR`.

## Sources

- [drduh/pwd.sh on GitHub](https://github.com/drduh/pwd.sh)
- [License: MIT](https://github.com/drduh/pwd.sh/blob/main/LICENSE)
- [Project website](https://drduh.github.io/pwd.sh/)
- [README](https://github.com/drduh/pwd.sh/blob/main/README.md)
- [Releases](https://github.com/drduh/pwd.sh/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/drduh-pwd-sh
