Introduction¶
When performing interface security testing on a DSH Agent, the two most expensive steps in manually verifying privilege escalation or logic flaws are not “sending one packet,” but constructing comparative requests and then determining response differences. rannyrjjy/dsh-fuzz automates these two steps: it performs differential fuzzing and logic testing on top of the diffprobe package engine. The process is fixed as sampling values → planning → executing → judging, and is read-only by default. Below is an introduction to its capabilities, installation method, and usage.
What is this¶
The plugin maintainer is rannyrjjy, with 1 star on GitHub, and classified as a workflow in the community directory. The plugin registers only one DSH Host tool, fuzz, responsible for parameter mapping and subprocess orchestration; all requests are always executed by engine/diffprobe, with no second request engine. Plans, seeds, original requests, and responses are all persisted to disk and do not enter the chat history.
It adheres to three verdict disciplines:
- Baseline comparability: Every payload carries a baseline and a same-type comparison to avoid treating “different lengths” as a vulnerability.
- Difference != Vulnerability: Distinguishing transport layer differences, error branches (
errorCode/errorMsg) from truly worth-reading state or data changes (ownerId/role/status/amount, etc.). - Verifiable:
runproducesdiffs.csv,verifyproducesstate.csv, andverdictonly performs classification; evidence is left in the workspace.
Note: This plugin is intended for authorized penetration testing, CTF/target ranges, and evaluation of own systems only.
Environment Requirements¶
- Node.js 22.19+ (or 24+)
- Python 3.9+, python / python3 in PATH
- DeepSeek Harness (Supports bundle plugins / Host tools)
The plugin is pure JS + Python with no build steps.
Installation and Enabling¶
# --profile is required: replace <profile> with your profile name (desktop usually)
# 1) Install from GitHub (public repository)
dsh plugin --profile <profile> add github:rannyrjjy/dsh-fuzz
# 2) Local install (after git clone / unzip, replace <plugin-dir> with absolute path)
dsh plugin --profile <profile> add file:<plugin-dir>
Local path syntax varies by platform: Windows uses file:D:\tools\dsh-fuzz, macOS/Linux uses file:/opt/dsh-fuzz. After installation, restart DeepSeek Harness (or let the plugin manager reload the profile), and the fuzz tool will appear in the tool list.
Update:
dsh plugin --profile <profile> update dsh-fuzz
# or remove then re-add
dsh plugin --profile <profile> remove dsh-fuzz
dsh plugin --profile <profile> add github:rannyrjjy/dsh-fuzz
Configuration¶
Default values are parsed in index.js and work without configuration. If you need to override, add a dsh-fuzz segment to the DSH patch layer:
- insert:
- id: dsh-fuzz
name: dsh-fuzz
config:
workspaceDir: /path/to/workspace # Recommended to configure explicitly: root for evidence, @file, diffprobe cwd
pythonPath: python3 # Default python on Windows
evidenceRoot: evidence # Name of evidence directory, default "漏洞记录"
timeoutMs: 300000
Windows paths can use C:/work/pentest or C:\\work\\pentest.
| Key | Default | Description |
|---|---|---|
workspaceDir |
DSH Host current directory (or DSH_FUZZ_WORKSPACE) |
Root of workspace; @file relative paths, diffprobe cwd, and evidence directory are all based on this |
pythonPath |
python (Windows) / python3 |
Python interpreter |
enginePath |
<plugin-dir>/engine/fuzz/fuzz_ops.py |
Engine entry point, can point to another engine |
evidenceRoot |
漏洞记录 |
Name of evidence directory, located under workspaceDir, can be renamed to anything |
timeoutMs |
300000 |
Single subprocess timeout (milliseconds) |
The engine also accepts environment variables (the plugin automatically injects the first three):
| Variable | Purpose |
|---|---|
DSH_FUZZ_WORKSPACE |
Same as workspaceDir |
DSH_FUZZ_EVIDENCE_DIR |
Same as evidenceRoot |
DSH_FUZZ_STATE |
Persistence location for plans/seeds/runs, default <workspace>/.dsh-fuzz |
DSH_FUZZ_ENGINE |
Engine root containing diffprobe/ and payloadsets/ |
fuzz Tool¶
The plugin exposes only one tool with six actions:
| action | What it does | Sends packet |
|---|---|---|
harvest |
Samples values with types (id/uuid/phone/token/email/amount, etc.) and field names from responses to generate seeds.json |
No |
plan |
Generates diffprobe plans (see kind table below), with baseline + same-type comparison, optional verify |
No (dryRun only validates) |
run |
Invokes diffprobe to execute plans, rate limiting, stopping on 403/429/503 hits; requires allowWrite for write methods |
Yes |
verdict |
Reads diffs.csv/state.csv for classification |
No |
doctor |
Checks if Python, engine, and payloadsets are ready | No |
bizmap |
Reads/writes target business map <workspace>/<evidenceRoot>/<target>/fuzz-bizmap.json |
No |
plan kind¶
| kind | Purpose |
|---|---|
chain |
Moves returned values from other interfaces to target parameter positions (BOLA/Reference chain) |
idor |
Neighbor/Comparison/Other user IDs, paired with verify to read owner fields back |
massassign |
Appends role/isAdmin/tenantId etc. to JSON body, checking if persisted |
role / tenant / amount |
Candidate fields for role, tenant, and amount |
param |
Appends hidden parameter names |
bypass |
Path segment normalization bypasses (%61dmin, admin/, admin/..;/, ..%2f, etc.) |
sqli xss ssrf lfi ssti cmdi xxe |
Reusing classic payload sets from engine/payloadsets/ |
Verdict criteria¶
| Category | Meaning |
|---|---|
DIFFERENTIAL |
Engine determines differential, or semantic layer judges DIFF |
INVALID |
Baseline itself unreachable—conclusion is invalid, not “no difference” |
BLOCKED |
Hit protection (403/429/503, etc.) |
STATE_CHANGED |
JSON path read back by verify actually changed |
NO_SIGNAL |
Others |
Differentials are further graded by “what changed”: state-or-data (changes in ownerId/userId/role/status/amount etc.) are worth expanding the sample; error-channel (only changing errorCode/errorMsg) is just an error branch or protection layer, do not treat as a vulnerability.
Typical Usage¶
Use python on Windows, python3 on macOS/Linux. Execute three offline self-check steps from the repository root (example spec does not contain real targets, offline, no network, no packets sent):
# 1) Environment self-check
python engine/fuzz/fuzz_ops.py --spec examples/doctor.json
# 2) Sample values from example responses (offline)
python engine/fuzz/fuzz_ops.py --spec examples/harvest.json
# 3) Generate idor plan and dry-run (offline, no network, no packets)
python engine/fuzz/fuzz_ops.py --spec examples/plan-idor.json
The engine also has an offline self-test server, listening only on 127.0.0.1, used to verify the differential judgment logic itself without producing external network requests:
python engine/diffprobe/selftest_server.py
Directory Structure¶
dsh-fuzz/
├─ index.js # DSH plugin: registers fuzz tool, forwards to engine
├─ cordis.patch.yml # bundle patch (single line insert)
├─ engine/
│ ├─ fuzz/ # fuzz_ops.py (plan/execute/judge), fuzz_verify.py (state read back), bench_verdict.py (judgment regression)
│ ├─ diffprobe/ # Request execution engine: rate limiting, destructive payload gates, differential and semantic comparison
│ └─ payloadsets/ # Shared payload sets (sqli/xss/idor/logic_*/fuzz_params, etc.)
├─ examples/ # Example specs without real targets
└─ locale/ # Plugin title and description
Applicable Scenarios and Notes¶
Suitable for DSH developers and security testing workflows that need to perform differential verification of privilege escalation and logic flaws on APIs within an authorized environment. Three points to note:
- Read-only by default:
POST/PUT/PATCH/DELETEmust explicitly haveallowWrite: true. Destructive payload rejection, rate limiting, and stopping on protection hits are all performed by diffprobe; plans cannot bypass this. - Evidence is persisted to
<workspace>/<evidenceRoot>/<target>/evidence/fuzz/or<workspace>/.dsh-fuzz/runs/; target authentication materials (Cookie/Token) only appear in the original requests you provide, the plugin does not persist them. - Known limitations:
raceconcurrency andstatestate machine generation are not yet implemented (schema reserved), currentrunwill skip plans withkind=race;verifyis “read back after a batch finishes”, which works for single-value plans, but continuous write payloads accumulate state; if you need isolation per payload, please split the plan.
The plugin runs with the current dsh process permissions. You should check the plugin source code and license (MIT) before installing. Current version is 0.1.2, requires DSH >=0.2.0-rc.2 || >=0.2.1-rc.2 || >=0.2.2-rc.1.
Directory page and source code:
- Community directory: https://www.skillhub.cn/plugins/rannyrjjy/dsh-fuzz
- GitHub: https://github.com/rannyrjjy/dsh-fuzz