Back to skill

Security audit

Deep Research

Security checks for vulnerabilities and agentic risk

Overview

This is a legitimate research-ledger skill, but its helper script can be directed to read or write a ledger file outside the intended .deepresearch folder.

Review this skill before installing. It appears intended for legitimate research tracking, but only use it in workspaces where creating .deepresearch state is acceptable, avoid untrusted or path-like slugs, and prefer a fixed version that validates slugs and confirms activation for non-/deepresearch prompts.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/deepresearch.py:25
Finding

Path Traversal Through Unvalidated Ledger Slug

Content
View full analysis
Path: if slug: return ROOT / slug current = ROOT / 'current' if current.exists(): target = current.read_text().strip() if target: return ROOT / target raise SystemExit('No slug supplied and .deepresearch/current is missing. Run init first.') ``` ```python def write_json(path: Path, data: Any) -> None: path.parent.mkdir(parents=True, exist_ok=True) tmp = path.with_suffix(path.suffix + '.tmp') tmp.write_text(json.dumps(data, indent=2, ensure_ascii=False) + '\n') tmp.replace(path) ``` ```python def cmd_init(args: argparse.Namespace) -> None: slug = args.slug or slugify(args.question) path = ROOT / slug data = ledger(path) data['question'] = args.question data['slug'] = slug if not data['lanes']: data['lanes'] = [ {'id': 'L001', 'name': 'background', 'question': 'What is the necessary context?', 'status': 'open'}, {'id': 'L002', 'name': 'evidence', 'question': 'What is the strongest evidence?', 'status': 'open'}, {'id': 'L003', 'name': 'counterevidence', 'question': 'What contradicts or weakens the claim?', 'status': 'open'}, {'id': 'L004', 'name': 'synthesis', 'question': 'What conclusion follows from the evidence?', 'status': 'open'}, ] save(path, data) ``` ### Technical Analysis The `--slug` command-line argument is treated as a filesystem path component without validation or canonical containment checks. In Python's `pathlib`, joining `ROOT` with an absolute path discards `ROOT`; relative components such as `..` can also escape the intended `.deepresearch` di ...[truncated 2760 chars]
Remediation
View remediation
str: if not SLUG_RE.fullmatch(slug): raise SystemExit('Invalid slug.') return slug ``` This rejects absolute paths, directory separators, `..`, empty values, and platform-specific path syntax. 2. **Enforce canonical containment before every read or write** Resolve the ledger root and candidate destination, then verify that the destination remains beneath the root: ```python ROOT = Path('.deepresearch').resolve() def safe_run_dir(slug: str) -> Path: slug = validate_slug(slug) candidate = (ROOT / slug).resolve() if candidate.parent != ROOT: raise SystemExit('Ledger path escapes .deepresearch.') return candidate ``` A robust implementation may use `candidate.relative_to(ROOT)` and reject `ValueError`. Do not rely exclusively on textual checks for `..`. 3. **Validate persisted state** Apply the same slug validation and canonical containment checks to the value read from `.deepresearch/current`. Treat this file as untrusted or potentially corrupted input. 4. **Address symlink traversal** Before writing, reject symlinks in the path chain or use secure directory-relative file operations that prevent following attacker-controlled links. Recheck containment as close as possible to the file operation to reduce time-of-check/time-of-use exposure. 5. **Avoid accepting path semantics where only identifiers are required** Keep `--slug` as a logical identifier rather than a path. If configurable storage paths are needed in the future, expose them through a separate, explicitly authorized option with dedicated validation. 6. **Add regression tests** Verify rejection of at least: - `../outside` - `../../ ...[truncated 341 chars]
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (2)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill instructs the agent to create and update durable state under .deepresearch/<slug>/ and repeatedly invoke scripts/deepresearch.py, which implies file read/write behavior, but it does not declare any explicit tool scope or permission boundaries. That mismatch is dangerous because consumers and enforcement layers cannot clearly constrain what filesystem access the skill expects, increasing the chance of unintended writes, broad workspace access, or abuse if the skill is triggered in a sensitive repository.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The invocation text is very broad: it applies not only to /deepresearch <question> but also to 'any request that needs more than a quick sourced answer,' plus many categories like due diligence, factual investigations, and reports. This can cause the skill to activate for a wide range of ordinary prompts, leading to unexpected file writes, script execution, and web-research behavior in contexts where the user did not explicitly request this workflow.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.