Back to skill

Security audit

Dia Ask Public

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly coherent, but it can use your logged-in Dia browser session and has under-scoped output/clipboard behavior that could expose or confuse sensitive local data.

Review before installing if you use Dia with sensitive accounts. Grant Accessibility only if you are comfortable with Node automating Dia, avoid using it on banking, admin, HR, or confidential tabs, consider --no-fallback for sensitive prompts to avoid clipboard use, and do not run it alongside other Dia tasks where an unrelated output file could be picked up.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
v2-lib.js:80
Finding

Output Discovery May Return an Unrelated Dia Work File

Content
View full analysis
onlyCtxs.includes(c)); for (const ctx of ctxs) { const wd = path.join(contextsDir, ctx, 'work'); for (const f of walk(wd)) { let st; try { st = fs.statSync(f); } catch { continue; } if (st.mtimeMs < sinceMs) continue; if (path.basename(f) === name) return f; if (!f.includes('/artifacts/') && st.mtimeMs > bestM) { bestM = st.mtimeMs; best = f; } } } return best; } ``` The v1 fallback contains the same behavior: ```js function findOutput(name, sinceMs) { let best = null, bestM = 0; let ctxs = []; try { ctxs = fs.readdirSync(CONTEXTS); } catch { return null; } for (const ctx of ctxs) { const wd = path.join(CONTEXTS, ctx, 'work'); for (const f of walk(wd)) { let st; try { st = fs.statSync(f); } catch { continue; } if (st.mtimeMs < sinceMs) continue; if (path.basename(f) === name) return f; if (!f.includes('/artifacts/') && st.mtimeMs > bestM) { bestM = st.mtimeMs; best = f; } } } return best; } ``` ### Technical Analysis Each request generates a unique expected filename such as `dia_out_1730000000000.md`. However, if that exact filename is not found, `findOutput()` returns the newest non-artifact file modified after `sinceMs`. Consequently, filename uniqueness is not enforced as a security or integrity boundary. Any other recent file in a scanned Dia work directory can be treated as the requested response. The behavior is i ...[truncated 2165 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
dia-ask.js:89
Finding

Fallback Sender Exposes Prompt Data Through the Global Clipboard and Restores Stale Clipboard State

Content
View full analysis
{ setClipboard(fullPrompt); osa(`tell application "Dia" to activate`); sleep(900); keystroke('n', ['command']); sleep(1600); try { osa(`tell application "System Events" to tell process "Dia" to click menu item "Enter Full Screen" of menu 1 of (menu bar item "View" of menu bar 1)`); } catch {} sleep(2500); keystroke('v', ['command']); sleep(700); pressReturn(); }; ``` Clipboard restoration occurs only when the entire operation exits: ```js } finally { if (saved !== null) setClipboard(saved); } ``` ### Technical Analysis When the v1 path is invoked directly, or when v2 automatically falls back to it, the complete prompt is placed in the system-wide clipboard. The prompt may include confidential research questions, identifiers, internal text, or other sensitive user input. The clipboard is not restored immediately after the paste. It remains populated with the prompt while the tool waits for chat startup and response generation, which may take several minutes according to the default timeout. The restoration logic is also unconditional. If the user or another application copies new content while the command is running, the `finally` block overwrites that newer clipboard value with the stale va ...[truncated 1621 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The manifest describes a browser-automation skill that can read logged-in or JS-heavy pages through a real browser session, but the analyzed code reportedly does not implement that behavior and instead primarily performs unrelated keymap unit testing. This mismatch is dangerous because users may grant trust, install, or authorize the skill based on misleading claims, masking hidden, incomplete, or swapped functionality and undermining security review.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 34)May include surrounding context.

md
- `dia-ask-v2.js` — default, **focus-safe** (injects into Dia's existing window via `CGEventPostToPid`; never steals focus).

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 35)May include surrounding context.

md
- `dia-ask.js` — v1 fallback (opens a fresh window, briefly takes focus). v2 falls back to it automatically; `--no-fallback` disables.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README explicitly promotes using Dia to read logged-in and JS-heavy pages in the user's real browser session and to write the extracted results to disk, but it does not prominently warn that prompts may cause sensitive authenticated content to be processed and persisted locally. In a skill whose core purpose is bridging an AI browser assistant with a local file output path, missing privacy guidance materially increases the chance of accidental exposure of private account data, paywalled content, internal documents, or secrets.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · dia-ask-v2.js (reported line 61)May include surrounding context.

js
if (process.env.DIA_DEADKEYS === '1') return true;
  if (process.env.DIA_DEADKEYS === '0') return false;
  try {
    const out = execSync('/usr/bin/defaults read ~/Library/Preferences/com.apple.HIToolbox.plist AppleSelectedInputSources 2>/dev/null', { encoding: 'utf8' });
    const m = out.match(/"KeyboardLayout Name"\s*=\s*"?([^";]+)"?/);
    return /international/i.test(m ? m[1] : '');
  } catch { return false; }

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · dia-ask-v2.js (reported line 175)May include surrounding context.

js
if (process.env.DIA_DEADKEYS === '1') return true;
  if (process.env.DIA_DEADKEYS === '0') return false;
  try {
    const out = execSync('/usr/bin/defaults read ~/Library/Preferences/com.apple.HIToolbox.plist AppleSelectedInputSources 2>/dev/null', { encoding: 'utf8' });
    const m = out.match(/"KeyboardLayout Name"\s*=\s*"?([^";]+)"?/);
    return /international/i.test(m ? m[1] : '');
  } catch { return false; }

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · keymap.js (reported line 87)May include surrounding context.

js
if (process.env.DIA_DEADKEYS === '1') return true;
  if (process.env.DIA_DEADKEYS === '0') return false;
  try {
    const out = execSync('/usr/bin/defaults read ~/Library/Preferences/com.apple.HIToolbox.plist AppleSelectedInputSources 2>/dev/null', { encoding: 'utf8' });
    const m = out.match(/"KeyboardLayout Name"\s*=\s*"?([^";]+)"?/);
    return /international/i.test(m ? m[1] : '');
  } catch { return false; }

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The comments explicitly describe altering Spanish text by removing accents before sending the prompt. This is a language-specific behavior that changes user input and reflects a locale/language constraint without offering the user a choice or opt-in.

Content

No source excerpt is available for this finding.

File System Enumeration

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Content

Scanner excerpt · dia-ask.js (reported line 53)May include surrounding context.

js
// bytes can get mangled (á -> "√°") through argv/exec. No-op on plain ASCII/English.
function deaccent(s) { const m = { 'á': 'a', 'é': 'e', 'í': 'i', 'ó': 'o', 'ú': 'u', 'ü': 'u', 'Á': 'A', 'É': 'E', 'Í': 'I', 'Ó': 'O', 'Ú': 'U', 'Ü': 'U' }; return String(s).replace(/[áéíóúüÁÉÍÓÚÜ]/g, (c) => m[c]); }

// Recursively list files under a directory (work dirs are shallow).
function walk(d, out = []) {
  let ents = [];
  try { ents = fs.readdirSync(d, { withFileTypes: true }); } catch { return out; }

File System Enumeration

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Content

Scanner excerpt · v2-lib.js (reported line 55)May include surrounding context.

js
// bytes can get mangled (á -> "√°") through argv/exec. No-op on plain ASCII/English.
function deaccent(s) { const m = { 'á': 'a', 'é': 'e', 'í': 'i', 'ó': 'o', 'ú': 'u', 'ü': 'u', 'Á': 'A', 'É': 'E', 'Í': 'I', 'Ó': 'O', 'Ú': 'U', 'Ü': 'U' }; return String(s).replace(/[áéíóúüÁÉÍÓÚÜ]/g, (c) => m[c]); }

// Recursively list files under a directory (work dirs are shallow).
function walk(d, out = []) {
  let ents = [];
  try { ents = fs.readdirSync(d, { withFileTypes: true }); } catch { return out; }

Vague Triggers

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

This is a manifest file, so vague trigger guidance applies. The description says the tool can "Prompt your locally-running Dia browser from the command line" but does not define specific trigger phrases, scope limits, or exclusion conditions, which can make activation criteria unclear in systems that infer invocation from manifest text.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
dia-ask-v2.js:36

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
dia-ask.js:43