Back to skill

Security audit

notify-hub

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a legitimate notification tool, but it handles powerful messaging credentials and outbound broadcasts in ways users should review carefully before installing.

Review this skill before installing in any workspace with sensitive reports or production alert channels. Treat every configured webhook, bot token, and SMTP password as a secret, avoid entering real credentials directly in shell commands, use --dry-run before live sends, specify --to explicitly, and avoid --to all unless the content is safe for every configured destination.

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
scripts/notify.py:34
Finding

Sensitive credentials exposed through command-line arguments

Content
View full analysis

Vulnerability Details

File Location: scripts/notify.py:34-38, 236-240
Vulnerability Type: Sensitive credential exposure through process arguments and shell history
Risk Level: Medium

Vulnerable Code

python
CRED_FLAGS = [
    ("url", "url"), ("secret", "secret"), ("token", "token"),
    ("chat-id", "chat_id"), ("smtp-host", "smtp_host"), ("port", "port"),
    ("user", "user"), ("password", "password"), ("to", "to"), ("sender", "sender"),
]
python
a.add_argument("channel", help="通道名(feishu/wecom/dingtalk/slack/telegram/email)")
a.add_argument("target", help="目标名(如群名/收件人)")
for flag, dest in CRED_FLAGS:
    a.add_argument(f"--{flag}", dest=dest, default=None)

The documented usage also encourages literal credentials in command lines:

bash
notify config add feishu 我的群 \
  --url https://open.feishu.cn/open-apis/bot/v2/hook/xxx \
  --secret xxx

Technical Analysis

The CLI accepts webhook URLs, bot tokens, signing secrets, and SMTP passwords as ordinary command-line options. Command-line arguments are not an appropriate secret-ingestion mechanism because they can be retained in shell history, terminal session logs, command auditing systems, and automation logs. Depending on the host configuration, process arguments may also be observable by other local processes while the command is running.

The application subsequently restricts the saved configuration file to mode 0600, which is a useful control for credentials at rest. However, that permission does not protect credentials before storage when they are present in the command line.

Webhook URLs are also credentials in this context: Feishu, WeCom, DingTalk, and Slack webhook URLs contain tokens that authorize message submission. Exposure therefore affects more than the explicitly named --secret, --token, and --password options.

Attack Path

  1. A user follows the documented configuration workflow an ...[truncated 1722 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove sensitive values from ordinary CLI options. Prompt interactively with getpass.getpass() for passwords, tokens, and signing secrets.
  2. Support a protected configuration file or secret-manager integration. Where automation is required, accept secrets through restricted file descriptors or files with verified ownership and 0600 permissions.
  3. If environment-variable support is added, document that environment variables may also be exposed by process diagnostics and should only be used where the runtime protects them.
  4. Treat webhook URLs as secrets because authentication tokens are embedded in them. Provide secure interactive input for --url, or support a protected input file.
  5. Retain the existing 0600 permission on the saved configuration, but create the file atomically with restrictive permissions rather than writing it under the process umask and applying chmod afterward.
  6. Update SKILL.md, README.md, and other examples so they do not encourage literal secrets on command lines.
  7. Add tests confirming that secret prompts do not echo input and that status messages never print credentials.
  8. Advise existing users to remove credential-bearing commands from shell history and rotate any credentials previously supplied this way.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (22)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill advertises and operationally depends on sensitive capabilities including network access, local file reads/writes, environment access, and shell execution, but it does not declare any explicit tool scope or permission boundaries. In an agent ecosystem, this increases the chance the skill is invoked with excessive privileges, enabling unintended exfiltration of secrets, unauthorized message sending, or unsafe file/shell operations if the implementation or downstream prompts are abused.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger conditions use very broad verbs like 推送/发送/通知/广播 and cover common reminder/reporting scenarios, which can cause over-invocation of a skill that sends data to external channels. Because this skill performs outbound dispatch to chat platforms and email, ambiguous triggering raises the risk of accidentally broadcasting sensitive or unreviewed content to multiple recipients.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger list includes broad, everyday terms such as '通知', '推送', and '广播' that can match many unrelated user requests, increasing the chance this skill activates when the user did not explicitly intend to send outbound messages. In a notification/broadcast skill, unintended activation is more dangerous than usual because it can cause accidental delivery of sensitive or misleading content to external channels.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The http_json helper sends arbitrary JSON payloads to a remote URL via POST, which can transmit user or system data off-host. In this file there is no confirmation prompt, logging/print statement, or explanatory warning comment/docstring indicating that outbound network transmission occurs or what data may be sent.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The module-level docstring presents the skill description entirely in Chinese and labels the channel as '邮件', with no indication that users can choose another language or locale. Per the policy, forcing a specific language without opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

This code sends the provided payload to an external Slack webhook URL via HTTP POST, which can transmit user or system data off-host. The implementation has no confirmation prompt, logging/print statement, or inline comment/docstring warning users that message contents will be sent to Slack.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/channels-schema.md (reported line 14)May include surrounding context.

md
rate_per_min = 30

    def _api(self, token, method):
        return f"https://api.telegram.org/bot{token}/{method}"

    def render_text(self, m):
        return {"method": "sendMessage", "data": {"text": m.get("text", "")}}

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/channels/telegram.py (reported line 20)May include surrounding context.

python
rate_per_min = 30

    def _api(self, token, method):
        return f"https://api.telegram.org/bot{token}/{method}"

    def render_text(self, m):
        return {"method": "sendMessage", "data": {"text": m.get("text", "")}}

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code sends message data to the external Telegram Bot API via HTTP POST, but there is no confirmation prompt, print/log statement, or explanatory comment/docstring near the operation describing that user content and chat identifiers are transmitted off-system. For a code file, outbound network transmission of user or system data should have some visible disclosure unless clearly documented elsewhere, which is not evident in this file.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This function uploads an arbitrary local file path to Telegram once invoked, which creates a real data exfiltration risk if untrusted callers can influence the file path or trigger dispatch without clear authorization boundaries. In the context of a multi-channel notification skill, file sending is expected, but the danger is higher because local filesystem contents may be transmitted off-host to a third-party service with no path allowlisting or sensitivity checks in this code.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The code writes channel credentials such as URLs, tokens, SMTP usernames, and passwords into ~/.notify-hub/config.json, but there is no user-facing warning at the point of saving that sensitive data will be stored locally. Although file permissions are restricted with chmod 600, the operation still persists secrets and the CLI output only confirms addition of the target without disclosing this behavior.

Content

No source excerpt is available for this finding.

Tainted flow: 'DEFAULT_CONFIG' from os.environ.get (line 29, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
84% confidence
Finding

The config file path is taken from the NOTIFY_CONFIG environment variable and then written without validation. In an agent or automation context, untrusted environment control could redirect credential-bearing config writes to unintended locations, causing secret exposure, file clobbering, or persistence in unsafe paths.

Content

Scanner excerpt · scripts/notify.py (reported line 50)May include surrounding context.

python
def save_config(cfg):
    os.makedirs(os.path.dirname(DEFAULT_CONFIG), exist_ok=True)
    with open(DEFAULT_CONFIG, "w", encoding="utf-8") as f:
        json.dump(cfg, f, ensure_ascii=False, indent=2)
    try:
        os.chmod(DEFAULT_CONFIG, 0o600)  # 凭据敏感,仅本人可读

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The send file path builds a message from a local file and the skill supports external services including Slack, Telegram, Feishu, and email, but the code does not present any disclosure or confirmation that the selected file will be uploaded or transmitted off-system. The generic '发送消息' help text is not sufficient warning for a potentially privacy-impacting file transfer across multiple third-party channels.

Content

No source excerpt is available for this finding.

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · LICENSE (reported line 12)May include surrounding context.

text
permit persons to whom the Software is furnished to do so.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The HTML root sets lang="zh-CN", and all visible UI text is written in Simplified Chinese, which indicates the skill preview is fixed to a specific language/locale. The file does not provide any opt-in, alternative locale, or justification that this is intentionally region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The user-facing manifest description is entirely in Chinese, which may impose a language expectation without offering a choice or documenting that the skill is intended only for a Chinese-speaking context. Under the policy, locale-specific presentation should be opt-in or explicitly justified as region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file contains user-facing instructional content only in Chinese, starting from the title and throughout the full document. Under the policy rules, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale restriction is explicitly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The file's human-facing documentation strings and inline messages are written exclusively in Chinese, including labels such as '中文显示名', without indicating that another language is available. Under the stated policy, forcing a specific language without user opt-in is a locale/language policy concern.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

This code sends the provided payload to an external DingTalk webhook via self.http_json(url, payload), which may transmit user or system data off-host. In this file there is no confirmation prompt, logging/print statement, or comment/docstring near the operation explaining that outbound data is being sent.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The only natural-language description in this file is written in Chinese, with no indication that language choice is configurable or intentionally region-specific. Under the policy, forced language/locale without user opt-in can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The file's user-facing natural-language docstrings/comments are written only in Chinese, which can violate a language/locale policy when no user choice or justification is provided. This is a natural-language issue applicable to all file types, even though the operational code itself is simple.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/notify.py (reported line 73)May include surrounding context.

python
cfg = load_config()
    cred = {}
    for flag, dest in CRED_FLAGS:
        val = getattr(args, dest, None)
        if val is not None:
            cred[dest] = int(val) if dest == "port" else val
    if not cred:

Static analysis

No suspicious patterns detected.