Back to skill

Security audit

Email Sender Pro

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed SMTP email sender, but it needs Review because it can use the public skill file itself as a place to store mailbox credentials.

Only install or use this if you will keep real SMTP credentials out of `SKILL.md`. Prefer an untracked local env file or a proper secret store, use provider-issued app-specific SMTP authorization codes where available, and run dry-run validation before any real send.

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

Warning
Location
SKILL.md:11
Finding

SMTP Credentials May Be Stored in a Tracked Skill Definition

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:11-30; supporting implementation in scripts/send_email.py:83-118 and scripts/send_email.py:194-205
Vulnerability Type: Credential exposure through insecure configuration storage
Risk Level: Medium

Vulnerable Code

SKILL.md:11-30:

dotenv
# Provider preset: 126, qq, sina, aliyun, custom
EMAIL_PROVIDER=126

# If EMAIL_PROVIDER=custom, fill these yourself.
SMTP_HOST=smtp.126.com
SMTP_PORT=465

# true for SMTPS on port 465, false for STARTTLS on port 587.
SMTP_USE_SSL=true

# Usually the mailbox address.
SMTP_USERNAME=your_email_username

# 126 / QQ commonly use an SMTP authorization code here.
# Sina / Aliyun may use the mailbox password depending on account settings.
SMTP_PASSWORD=your_smtp_secret

FROM_EMAIL=your_email_username
FROM_NAME=your_name

# Seconds
SMTP_TIMEOUT=30

The sending script parses the embedded block from the Skill file and merges it into the active configuration in scripts/send_email.py:83-118:

python
def load_embedded_skill_config(path: Path) -> dict[str, str]:
    if not path.exists():
        return {}

    lines = path.read_text(encoding="utf-8-sig").splitlines()
    heading_index = next(
        (index for index, line in enumerate(lines) if line.strip() == EMBEDDED_CONFIG_HEADING),
        None,
    )
    if heading_index is None:
        return {}

    fence_start = None
    for index in range(heading_index + 1, len(lines)):
        stripped = lines[index].strip()
        if stripped.startswith("```dotenv") or stripped.startswith("```env") or stripped == "```":
            fence_start = index + 1
            break
        if stripped.startswith("## "):
            return {}

    if fence_start is None:
        return {}

    block_lines: list[str] = []
    for index in range(fence_start, len(lines)):
        stripped = lines[index].strip()
        if stripped == "```":
            break
        block_lines.append(lines[index])
    if not block_lines:

...[truncated 2925 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove support for loading SMTP_PASSWORD from SKILL.md. Skill documentation should contain placeholders only and must never function as a runtime secret source.
  2. Read the password from a process environment variable, operating-system credential manager, CI/CD secret store, or dedicated secrets-management service.
  3. If .env remains supported, add .env and similarly named local secret files to .gitignore, document that they must never be committed, and restrict their filesystem permissions.
  4. Separate non-sensitive provider defaults from secret values. Hosts, ports, and TLS modes may remain in tracked configuration, while authentication credentials must be supplied at runtime.
  5. Prefer provider-issued, revocable, application-specific SMTP authorization codes over normal mailbox passwords.
  6. Remove password previews from dry-run output. Even partial disclosure can reveal credential length and fragments and provides little operational value.
  7. Add secret-scanning checks to pre-commit and CI workflows to detect SMTP passwords, authorization codes, and accidentally populated configuration examples.
  8. If a real credential has ever been placed in SKILL.md, revoke or rotate it immediately and remove it from repository history and distributed artifacts.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/send_email.py (reported line 245)May include surrounding context.

python
def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="Send a simple email through SMTP.")
    parser.add_argument("--env-file", default=".env", help="Path to the .env file")
    parser.add_argument("--skill-file", default="SKILL.md", help="Path to the SKILL.md file")
    parser.add_argument("--to-email", help="Recipient email address")
    parser.add_argument("--email-subject", help="Email subject")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/send_email.py (reported line 245)May include surrounding context.

python
def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="Send a simple email through SMTP.")
    parser.add_argument("--env-file", default=".env", help="Path to the .env file")
    parser.add_argument("--skill-file", default="SKILL.md", help="Path to the SKILL.md file")
    parser.add_argument("--to-email", help="Recipient email address")
    parser.add_argument("--email-subject", help="Email subject")

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill instructs the agent to read a root .env file and to fall back to embedded SMTP configuration, which means it uses file-read and secret-handling capabilities without declaring any explicit tool scope or permission boundary. In an agent framework, missing tool restrictions can allow broader-than-expected access to local files and environment-derived secrets, increasing the chance of unintended secret exposure or misuse during email-sending workflows.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.