Back to skill

Security audit

Agentic Payment Daily

Security checks for vulnerabilities and agentic risk

Overview

This is a targeted daily report automation, but it needs review because it writes business reports locally, can run on a schedule, and sends PDFs to a hardcoded WeChat recipient.

Install only if this is your intended Visa/WeChat/Obsidian environment and you accept automatic delivery to the listed WeChat recipient. Before using cron or sharing reports, make the destination configurable, require confirmation for sends, restrict local paths, and fix the PDF converter to avoid shell-string execution and active unescaped HTML rendering.

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

Error
Location
scripts/convert-ap-report.mjs:145
Finding

OS Command Injection Through the PDF Output Path

Content
View full analysis
&1 || true`, { stdio: 'pipe', timeout: 30000 }); const generated = tmpHtml.replace(/\.html$/, '.pdf'); if (existsSync(generated)) { renameSync(generated, resolve(outputPdf)); console.log('OK'); } else { // Fallback: try node with puppeteer directly console.log('Fallback: trying direct puppeteer render...'); execSync(`node -e " const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({headless:'new'}); const page = await browser.newPage(); await page.goto('file://${tmpHtml}', {waitUntil:'networkidle0'}); await page.pdf({path:'${resolve(outputPdf)}', format:'A4', margin:{top:'18mm',bottom:'18mm',left:'18mm',right:'18mm'}, printBackground:true}); await browser.close(); console.log('OK'); })(); "`, { stdio: 'inherit', timeout: 30000 }); } ``` ### Technical Analysis The `outputPdf` value comes directly from `process.argv`. It is used to derive `tmpHtml` and is subsequently interpolated into command strings passed to `execSync`. The first invocation places `tmpHtml` inside double quotes, but shell substitutions such as `$(command)` remain active inside double-quoted shell arguments. The fallback also embeds both `tmpHtml` and `resolve(outputPdf)` in a shell command containing inline JavaScript. Crafted quote characters, command substitutions, or JavaScript delimiters can therefore escape the intended path context. Because `execSync` executes through a shell, string interpolation converts an otherwise ordinary output filename into a command-execution primitive. No filename validation or restriction to an approved output directory is p ...[truncated 1443 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/convert-ap-report.mjs:53
Finding

Unescaped Report Content Rendered as Active Local HTML

Content
View full analysis
${currentEnP}`; currentEnP = ''; } i++; continue; } if (line.startsWith('- 💡') || line.match(/^-\s*💡/)) { const c = line.replace(/^-\s*💡\s*\*\*(?:So What[^::]*[::])\*\*\s*/, '').replace(/\*$/g, '').trim(); content += `
So What: ${c}
`; } else if (line.startsWith('- 🎯') || line.match(/^-\s*🎯/)) { const c = line.replace(/^-\s*🎯\s*\*\*(?:Action Item[^::]*[::])\*\*\s*/, '').replace(/\*$/g, '').trim(); content += `
Action Item: ${c}
`; } else if (line.startsWith('🔗')) { // Extract URLs from this line const urls = line.match(/https?:\/\/[^\s)]+/g) || []; const linksHTML = urls.map(u => { // Shorten URL for display let display = u; try { display = new URL(u).hostname + (u.length > 60 ? '...' : ''); } catch(e) {} return `${display}`; }).join('   '); content += `

Source: ${linksHT ...[truncated 3515 chars]

Remediation
View remediation
', '>') .replaceAll('"', '"') .replaceAll("'", '''); } ``` Apply this function to titles, summaries, action items, bullet text, dates, labels, and link display text. 2. Validate source URLs using `new URL()` and allow only explicit protocols such as `https:` and, if required, `http:`. Escape the validated URL before placing it in an HTML attribute. 3. If limited report markup must be supported, use a maintained HTML sanitizer with a strict allowlist. Do not permit scripts, event-handler attributes, iframes, embedded objects, forms, or arbitrary styles. 4. Disable JavaScript in the PDF-rendering page when it is not required: ```js await page.setJavaScriptEnabled(false); ``` 5. Use Puppeteer request interception to block all network requests or permit only explicitly approved resources. The report already contains inline styling, so external network access should not be necessary for rendering. 6. Keep the browser sandbox enabled and run the renderer under a dedicated, least-privileged account with access only to the temporary input and output files. 7. Create temporary files in a private directory with restrictive permissions and remove them after rendering. 8. Add security tests containing HTML elements, event handlers, quote characters, external-resource tags, and malformed URLs to verify that the resulting document contains only inert text. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (5)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill automatically transmits the generated report to a fixed WeChat recipient and account without any privacy warning, approval checkpoint, or data-classification control. This is dangerous because the report may contain sensitive business intelligence, internal analysis, or regulated information, and the hardcoded external delivery target makes accidental or unauthorized disclosure much more likely.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill instructs the agent to write directly to a user-specific local Obsidian vault path without any user confirmation, safety notice, or scoping guard. This creates a real integrity risk because the agent can modify local files on disk, potentially overwriting notes, creating unexpected artifacts, or exposing sensitive workspace structure through automated operation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The generated document sets <html lang="zh-CN">, which forces a specific locale in output regardless of user preference. The file does not offer a language/locale option or document why this constraint is required, matching the policy category for locale restrictions without opt-in.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The comments at L143-L145 say the script will 'use puppeteer directly' and frame the approach as rendering via md-to-pdf, but the implementation uses execSync to run external CLI commands and, on fallback, spawns a separate node -e subprocess rather than using Puppeteer in-process. This is an intent/documentation contradiction, not merely omitted detail, because the comments describe a different execution model than the one actually used.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The skill directs the agent to generate a PDF in /tmp as a local artifact without notifying the user or obtaining approval. While /tmp is less sensitive than a persistent user directory, silent artifact creation can still leak report contents to other local processes or leave behind sensitive material unexpectedly.

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
scripts/convert-ap-report.mjs:147