Bundle
dsh-path-anonymizer
DSH plugin: anonymize workspace-external file paths before model requests with user confirmation
- Source
- yzhangjy
- License
- MIT
- Updated
- Updated 7 days ago
Readme
# dsh-path-anonymizer
English | [中文](README.zh.md)
A DeepSeek Harness plugin that detects workspace-external file paths in user messages before model requests, replaces them with numbered placeholders (`[PATH_n]`), and prompts the user to confirm whether the real paths should be sent to the model.
## Installation
```bash
dsh plugin --profile web add github:yzhangjy/dsh-path-anonymizer
```
Then restart the web profile.
## How It Works
1. **Detection** — regular expressions scan each user message for file paths.
2. **Anonymization** — each detected path is replaced with a numbered placeholder:
```
/Users/alice/Documents/project/src/main.ts → [PATH_1]
/etc/nginx/nginx.conf → [PATH_2]
~/secrets/.env → [PATH_3]
```
**Workspace awareness** — paths that resolve *inside* the agent's working
directory (`cwd`) are left untouched: the model already sees `cwd` in the
system prompt and can explore the workspace itself, so anonymizing those
would break coding with no privacy gain. Only paths *outside* the workspace
(`~/...`, `/etc/...`, other projects, …) are anonymized. Set
`anonymizeWorkspacePaths: true` to revert to anonymize-everything.
3. **Confirmation** — before the model request proceeds, a dialog appears listing every detected path and its placeholder. The user chooses:
- **Send anonymized placeholders** (recommended) — the model sees `[PATH_n]`
- **Send real paths** — original paths are restored
- **Cancel this request** — the step is rejected
4. **Session memory** — the dialog includes a "remember" option so the same choice applies for the rest of the session.
### Effect on tool calls
Anonymization redacts **only the user-message text**. That does affect tool calls
in one specific way:
- When an external path is anonymized, the model sees `[PATH_n]` instead of the
real path, so it **cannot call `read` / `edit` / `bash` on that path** — it does
not know the real path. It will usually ask you to reveal it instead.
- Choosing **"send real paths"** in the dialog sends the path verbatim, so the
model can access that external path normally.
This plugin is **message redaction, not a security sandbox**. It does not filter
the model's own tool calls, tool arguments, or tool results, and it does not
restrict filesystem access (DSH's sandbox governs that separately). A path the
model learns from a tool result or from its own exploration is **not** anonymized.
Workspace paths are untouched, so reading and editing files inside the workspace
works as usual.
## Configuration
| Key | Default | Description |
|---|---|---|
| `enabled` | `true` | Enable path detection and anonymization |
| `confirmEveryTime` | `true` | Show the confirmation dialog for every request |
| `maxPathsPerPrompt` | `10` | Max paths displayed in the confirmation dialog |
| `autoAnonymize` | `false` | Silently replace paths without showing a dialog |
| `anonymizeWorkspacePaths` | `false` | Also anonymize paths inside `cwd` (default keeps them for coding) |
| `detector.maxPaths` | `50` | Max distinct paths to detect in one batch |
| `detector.excludePatterns` | `[]` | Extra regex patterns for paths to ignore |
| `detector.includeSystemPaths` | `false` | Also detect system paths (`/usr/lib/`, `/etc/`, etc.) |
| `anonymizer.placeholderFormat` | `[PATH_{n}]` | Placeholder format; `{n}` is the match index |
### Example: auto-anonymize mode
```yaml
- id: path-anonymizer
config:
enabled: true
autoAnonymize: true # never shows a dialog
```
### Example: exclude additional patterns
```yaml
- id: path-anonymizer
config:
detector:
excludePatterns:
- '^/nix/store/'
- '^/home/ci/'
```
## Path Detection Details
### Matched patterns
| Pattern | Example |
|---|---|
| Unix absolute | `/Users/alice/project/src/index.ts` |
| Windows absolute | `C:\Users\alice\Documents\file.txt` |
| Home directory | `~/.ssh/config` |
| Relative (`./`) | `./src/components/App.tsx` |
| Relative (`../`) | `../../config/database.yml` |
| Windows relative | `.\lib\utils.js` |
| Env variable | `%APPDATA%\MyApp\settings.json` |
| WSL | `\\wsl$\Ubuntu\home\user\file.txt` |
### Excluded by default
- URLs (`https://`, `ftp://`, `file://`)
- Shell redirects (`/dev/null`, `/dev/stdout`)
- System paths (`/usr/lib/`, `/etc/`, `/proc/`, `/sys/`, `C:\Windows\`) when `includeSystemPaths` is false
- Protocol-relative URLs (`//`)
- Lone slash (`/`)
## Known Limitations
- **Regex-only detection** — paths embedded in complex code syntax may be missed or falsely matched. The patterns balance recall against false positives for natural-language chat messages.
- **No filesystem validation** — a string that looks like a valid path is treated as one; the plugin does not check whether the file actually exists.
- **Message content only** — detection operates on text blocks within messages; non-text content blocks (images, tool calls) are not scanned.
- **One dialog per request** — a batch with paths in several messages shows one combined dialog, not one per path.
Install
dsh plugin --profile web add github:yzhangjy/dsh-path-anonymizer
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-path-anonymizer from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.