Install verification: runtime verified (L5) · tested on dsh 0.2.1-rc.2 · last checked Install verification details →
What it does
把 DSH Web 界面换成自家品牌(Logo / 名称 / 中央标题 / favicon),并给页面与项目文件夹打上「为什么加 · 在干什么」水印。Rebrand your DSH web UI and stamp "why added / what job" watermarks on pages and project folders.
Installation
dsh plugin --profile web add dsh-brand-textInstall method: npm · runtime verified (L5)
Verification & Compatibility
Grouped by plugin version: each card lists the dsh versions actually tested against that artifact version and their install verdicts (L5 wins). Untested combinations are omitted — absence means untested, never assumed compatible. L1–L3 are a plugin-level static archive (independent of the dsh version — the same verdict on every dsh row): they sit in each row's level grid next to L4/L5, marked "static", while their evidence is stored once per plugin inside that row's "checks & evidence" instead of being duplicated per version.
External credentials (plugin-level): none detected
○ The author declares no dsh version requirement — install is not blocked by version.
| plugin \ dsh | dsh 0.2.1-rc.2 current |
|---|---|
| 0.4.0 | ✓ |
0.4.0npm✓ 1 runtime-verified2026-10-21
dsh-brand-text
✓dsh 0.2.1-rc.2current2026-10-21L5 · runtime verified
- • Node.js: v24.14.0
- • DSH: 0.2.1-rc.2
- • Plugin artifact: npm · dsh-brand-text@0.4.0
ID: dsh-brand-text@0.4.0@dsh0.2.1-rc.2 · profile: l3-fullscan
Issued: 2026-10-21 · expires: 2026-10-28
View checks & evidence
active in loader tree (150 entries)
L1–L3 are plugin-level static conclusions (baseline, identical across dsh versions): evidence is stored once per plugin.
Only the latest 3 published versions are shown; source-snapshot (commit hash) groups, unstated groups and older versions are omitted — the full archive stays in the data layer (snapshot/unstated groups appear only when a plugin has no published version).
Author badges
Embed the official badges in your README to showcase security & install-test status:
`[](https://www.dsh.so/artifact/dsh-brand-text/)``[](https://www.dsh.so/artifact/dsh-brand-text/)`Security Report
Two automated layers, neither a manual review: a static scan (per-plugin rule checks) and a model-driven dynamic security audit that covers only the subset static-flagged at warn or above and never executes plugin code.
Static low, dynamic high — stricter wins → overall high.
v0.4.0dsh manifest0.4.0npm2026-10-210.4.0same versionclean · npmVet is an AST static scan (npm artifact or git source).
show static findings (5)
- warningshellExec · shell
install.mjs:75execFileSync(cmd, args, { cwd: resolve(profileDir), stdio, env, shell: true }) - warningnetIp · network
install.mjs:77console.log(' http://127.0.0.1:<该 profile 的 DSH 端口>/brand-studio/') - warningshellExec · shell
lib/index.js:329execFile('explorer', [path], { windowsHide: true }, () => {}) - warningnetIp · network
lib/index.js:77return new URL(req.url || '/', 'http://127.0.0.1').searchParams - warningshellExec · shell
lib/watermark.js:179execFile('attrib', args, { windowsHide: true }, (err) => resolve(err ? String(err.message) : ''))
show 4 audit findings
- highUnauthenticated route writes/deletes files in any caller-supplied path (arbitrary filesystem write)
lib/index.js:296POST /brand-studio/api/watermark/target takes an arbitrary path, does stat() on it, writes `<name>.DSH水印说明.md`, `dsh-mark.ico` and `desktop.ini` (backing up an existing desktop.ini to desktop.ini.dshbak) into that directory, runs `attrib +h/+s`, and with remove:true deletes those files (no ledger check on the remove branch). There is no auth or CSRF protection: the handler JSON.parses the raw body regardless of Content-Type, so a cross-origin simple POST (no-cors, text/plain) or any local process can drive it. Paths may be UNC/network shares, which also leaks NTLM auth via stat()/writeFile. Co
- mediumexplorer launched on caller-chosen path; the 'ledger' allow-list is filled by the same unauthenticated endpoint
lib/index.js:329The guard checks the path against watermark.targets, but that list is written by /api/watermark/target, which the same caller controls: one POST to add any existing writable path, then POST /api/open with it. execFile without shell prevents shell injection, but explorer is then asked to open an attacker-selected local or UNC path (SMB credential exposure, opening arbitrary files/folders).
- mediumUploaded SVG logo is served from the DSH origin without CSP, giving stored XSS via /brand-studio/logo
lib/index.js:217Any caller that can reach /api/save (same CSRF/local-access caveat as above) can store an SVG containing script; it is later returned by GET /brand-studio/logo with image/svg+xml and no Content-Security-Policy. Navigating the victim to that URL executes script in the DSH origin, from which the other /brand-studio APIs and any same-origin DSH endpoints are reachable.
- lowInstaller runs package manager with execFileSync and shell:true
install.mjs:75With shell:true Node builds a shell command line; here cmd/args come from a hardcoded list and profileDir is only used as cwd, so no user-supplied string is currently injectable. It is a hardening gap only, but it makes any future change that interpolates arguments a command-injection bug, and it also runs a dependency install as part of ordinary setup.
Unauthenticated local HTTP routes accept attacker-chosen file paths: arbitrary write/delete via /api/watermark/target, and /api/open launches Explorer on a 'ledger' the same caller filled.
Rule: the dynamic audit can only raise risk, never lower it (raise-only, never an exemption); a wrong raise is withdrawn by human review and the tier falls back to the static verdict. Overall verdict = the stricter of the two layers.
Disclaimer: the static scan and the dynamic security audit are both automated analysis, not a security guarantee. Always review what you install.
Activity
Last commit 2026-10-17 · activity: Active
• Repo created: 2026-10-17
• Stars: ★ 1 · Forks: 0
• Health: Active — committed within last 30 days
Source
Author README
View on GitHub ↗The author's original README from the repository — fetched live, unedited (the English page loads the default README).
