api-relay-audit
toby-bridges
Local security audit for AI API relays and LLM proxies: detects prompt injection, model substitution, tool-call rewriting, SSE anomalies, error leakage, and Web3 wallet risks.
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:Linxiushen/dsh-workflow-isolate
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
简体中文 | Architecture | Security model | Compatibility
dsh-workflow-isolate is a drop-in WorkflowEngine for DeepSeek Harness that runs model-written orchestration scripts in QuickJS/WASM. It preserves the DSH workflow hooks and lifecycle events while adding an independent JavaScript runtime, bounded guest memory and stack, interrupt fuel, a host wall deadline, forced worker termination, and child-agent budgets.
DeepSeek Harness's official worker-thread engine deliberately uses node:vm as an API-shaping mechanism. Its documentation states that it is not a security boundary and calls for a different engine when scripts are not trusted. This project explores that engine seam without changing the model-facing workflow tool.
[!IMPORTANT] QuickJS/WASM is a stronger language boundary than
node:vm, not a claim of perfect isolation. The host-side subagent provider remains trusted and can use its configured model, tools, network, and credentials. Runtime vulnerabilities, side channels, supply-chain compromise, and host denial of service remain relevant. Read the security model before deploying it across trust boundaries.
Model-written workflow code sits in an unusual middle ground: it needs enough JavaScript to coordinate many agents, but it should not inherit Node.js authority merely because the harness is written in Node. dsh-workflow-isolate narrows that gap:
args, agent, parallel, pipeline, phase, and log; no process, require, Node module loader, filesystem, network, or timers are injected.WorkflowRun, never-rejecting results, bounded disposal, and paired workflow/* lifecycle events expected by DSH consumers.flowchart LR
T["DSH workflow tool"] --> E["IsolatedWorkflowEngine"]
E --> H["Host run controller"]
H --> W["Node worker thread"]
W --> Q["Fresh QuickJS/WASM realm"]
Q -->|"JSON child request"| H
H -->|"trusted host RPC"| S["ctx.subagents"]
S -->|"JSON result projection"| H
H --> Q
H --> O["workflow/* observers"]
The Node worker is a lifecycle and termination container. The QuickJS runtime inside it is the language boundary: guest constructors and prototypes belong to QuickJS, not V8, and no Node object is intentionally placed in the realm. See Architecture for the run sequence and Threat model for boundary assumptions.
The current release targets @deepseek-ai/dsh-workflow@0.1.0-rc.7 and the associated DSH 0.1.0-rc.7 workflow packages. DSH's workflow API is still a release candidate, so compatibility is intentionally version-bounded.
The following surfaces are retained:
ctx.workflowEngine service providerWorkflowStartRequest, WorkflowRun, and WorkflowResultagent, parallel, pipeline, phase, log, and argsworkflow/start, workflow/phase, workflow/log, workflow/agent-start, workflow/agent-end, and workflow/endQuickJS is not V8. Workflow bodies must use portable JavaScript and cannot depend on Node APIs, V8-only behavior, dynamic module loading, or ambient timers. Error text and stack formatting may also differ. The detailed behavior matrix is in Compatibility.
pnpm benchmark measures cold and warm fresh-runtime overhead and prints median/p95 JSON. The Node baseline is included only as a scale reference; it is not a security-equivalent engine. See the benchmark methodology.
Prerequisites: Node.js 22.19.x or 24.x, pnpm 11, a DSH 0.1.0-rc.7 installation, and a working spawn subagent provider.
git clone https://github.com/Linxiushen/dsh-workflow-isolate.git
cd dsh-workflow-isolate
corepack enable
pnpm install --frozen-lockfile
pnpm check
pnpm pack
Install the generated tarball into the DSH profile you use. A tarball includes built output and does not require a git dependency build allowance:
dsh plugin --profile web add ./dsh-workflow-isolate-0.1.0.tgz
dsh --profile web --dump-config
The bundled cordis.patch.yml disables the stock workflow-worker-thread row and inserts this engine. DSH permits one ctx.workflowEngine provider per context, so the two engines must not be mounted together.
For local source iteration, DSH also accepts a linked checkout after it has been built:
dsh plugin --profile web add .
The bundle ships with a conservative deployment profile:
- id: workflow-worker-thread
disabled: true
- insert:
- id: workflow-isolate
name: dsh-workflow-isolate
config:
provider: spawn
memoryLimitBytes: 67108864
maxInterruptTicks: 250000
maxAgentRequestBytes: 1048576
maxWallTimeMs: 600000
maxConcurrentAgents: 0
maxTotalAgents: 1000
maxItemsPerCall: 4096
disposeGraceMs: 3000
maxConcurrentAgents: 0 asks the engine to derive a bounded value from available CPU parallelism. A profile's own cordis.patch.yml is applied after bundle layers and can replace this row's config. Cordis row configs replace rather than deep-merge, so restate every value you need when overriding it.
Resource limits are deployment policy, not script options. Lower them for exposed or multi-user deployments, and remember that child-agent cost is primarily controlled by maxConcurrentAgents and maxTotalAgents, not QuickJS memory.
Millisecond timer settings are capped at Node.js's maximum single-delay value (2,147,483,647) so oversized values cannot be clamped to an immediate timeout.
All engine defaults are listed below. The bundle patch relies on static defaults for values it does not restate.
| Key | Default | Purpose |
|---|---|---|
provider |
spawn |
Host-side subagent provider |
memoryLimitBytes |
64 MiB | QuickJS guest heap ceiling |
maxStackBytes |
1 MiB | QuickJS interpreter stack ceiling |
maxInterruptTicks |
250,000 | QuickJS interrupt-fuel budget per run |
maxScriptBytes |
256 KiB | UTF-8 workflow body ceiling |
maxResultBytes |
1 MiB | UTF-8 serialized final-result ceiling |
maxAgentRequestBytes |
1 MiB | UTF-8 JSON ceiling for one prompt and its agent options |
maxWallTimeMs |
600,000 | Host-observed run deadline, including child waits |
workerMemoryLimitMb |
128 MiB | V8 old-generation ceiling for the worker bridge |
maxConcurrentAgents |
0 |
Auto-resolves to min(16, max(1, availableParallelism() - 2)) |
maxTotalAgents |
1,000 | Accepted agent() calls per run |
maxItemsPerCall |
4,096 | Items per parallel() or pipeline() call |
disposeGraceMs |
3,000 | Cleanup grace before forced worker termination |
The model-facing tool still receives meta, args, and a plain JavaScript function body. A body can fan research questions out through structured child calls and then synthesize the surviving results:
phase("Research");
const findings = await pipeline(args.questions, async (question) =>
agent("Investigate this question and cite concrete evidence: " + question, {
label: question,
schema: {
type: "object",
properties: {
answer: { type: "string" },
evidence: { type: "array", items: { type: "string" } },
},
required: ["answer", "evidence"],
additionalProperties: false,
},
}),
);
phase("Synthesis");
const usable = findings.filter(Boolean);
const summary = await agent(
"Synthesize these findings for " +
args.audience +
":\n" +
JSON.stringify(usable),
{ label: "Final synthesis" },
);
return { findings: usable, summary };
See the complete importable request fixture in examples/research-synthesis.mjs, including metadata and sample arguments.
start() returns, run.result resolves rather than rejects. Completion, cancellation, and failures are represented by stopReason.workflow/agent-start is paired once with workflow/agent-end, including host-synthesized cancellation ends after forced termination.IsolatedRun also exposes metrics: Promise<IsolateMetrics> with runtime, wall time, interrupt ticks, optional settlement-time memoryUsedBytes, and a termination classification. This is a project extension, not part of the upstream WorkflowRun interface.pnpm install --frozen-lockfile
pnpm check
pnpm check runs linting, TypeScript validation, tests, the production build, a real worker smoke against that build, and package-surface validation. CI covers the supported Node.js lines. Security-relevant changes should include adversarial tests for escape attempts, cancellation races, budget exhaustion, and lifecycle pairing.
See Contributing, Security policy, and the Changelog.
This is an independent, experimental provider for a release-candidate DeepSeek Harness seam. It is not an official DeepSeek project and has not been independently audited. The 0.x version line may track breaking changes in DSH until the upstream workflow API stabilizes.
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: sandbox、workflow-engine。