Back to skill

Security audit

Nomtiq

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches a restaurant recommendation purpose, but it can silently use an undeclared Baidu Maps credential/provider and documents an unpinned global install path.

Review before installing. Use the OpenClaw install path rather than the unpinned npx global command, only expose the API keys you intend this skill to use, and unset BMAP_KEY unless you explicitly want Baidu Maps involved. Be aware that restaurant preferences, locations, companion notes, scene history, and feedback are stored locally in the skill data directory.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/search_maps.py:249
Finding

Undeclared Baidu Provider Automatically Uses an Ambient Credential

Content
View full analysis

Vulnerability Details

File Location: scripts/search_maps.py:249-275 and scripts/search_maps.py:468-475
Vulnerability Type: Undeclared external provider and ambient credential use
Risk Level: Medium

The documented provider boundary in SKILL.md:20-31, SKILL.md:101-105, and README.md:34-49 lists only Amap and Serper. The implementation nevertheless activates Baidu Maps whenever the Agent process happens to contain a BMAP_KEY.

python
BMAP_KEY = os.environ.get('BMAP_KEY', '')


def search_bmap(query: str, city: str = '', district: str = '',
                max_results: int = 20) -> list:
    """百度地图地点检索"""
    if not BMAP_KEY:
        print("⚠️  未配置 BMAP_KEY,跳过百度搜索", file=sys.stderr)
        return []

    region = district or city

    params = {
        'ak': BMAP_KEY,
        'query': query,
        'region': region,
        'output': 'json',
        'page_size': min(max_results, 20),
        'page_num': 0,
        'scope': 2,
        'filter': 'industry_type:cater',
    }

    url = f"https://api.map.baidu.com/place/v2/search?{urlencode(params)}"

The provider is then invoked automatically during a normal mainland-China search:

python
bmap = []
if BMAP_KEY:
    print(f"🗺️  百度地图搜索(可选)...", file=sys.stderr)
    bmap = search_bmap(query, city or district, district, max_results)
    print(f"   百度: {len(bmap)} 家", file=sys.stderr)

merged = merge_cn_sources(amap, bmap)

Technical Analysis

The module reads BMAP_KEY from the ambient process environment at import time. A normal China search checks only whether that variable is present and then sends the key, restaurant query, and city or district to https://api.map.baidu.com.

There is no explicit provider selection or per-request consent. Baidu Maps is also absent from the Skill's declared external-call metadata and conflicts with the documented statement that restaurant queries and destination ...[truncated 1425 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove the Baidu integration if Amap is intended to be the sole mainland-China provider.
  2. If Baidu support is retained, declare https://api.map.baidu.com, BMAP_KEY, the transmitted fields, and the provider purpose in SKILL.md, README.md, and Skill metadata.
  3. Require explicit opt-in or an explicit provider-selection argument before accessing BMAP_KEY or contacting Baidu.
  4. Read the credential only inside the explicitly selected provider path rather than at module import time.
  5. Ensure the router invokes exactly one selected primary provider unless the user has separately enabled a documented cross-verification provider.
  6. Add tests confirming that an ambient BMAP_KEY alone cannot trigger an outbound request.
  7. Update privacy documentation to identify every possible data recipient and explain when cross-provider disclosure occurs.

T08 · Insecure Dependencies

Warning
Location
README.md:15
Finding

Unpinned Third-Party CLI Performs a Global Skill Installation

Content
View full analysis

Vulnerability Details

File Location: README.md:15-18
Vulnerability Type: Unpinned supply-chain installation command
Risk Level: Medium

bash
npx skills add oakcoderx/nomtiq -g

Technical Analysis

The installation instruction invokes the mutable skills package through npx without pinning the CLI to a reviewed version. It also identifies the target Skill through a mutable repository-style name rather than an immutable commit, release digest, or verified artifact.

npx may download and execute package code that was not part of this audited project. The -g option then installs the resulting Skill globally, increasing the persistence and scope of a compromised installation.

No malicious dependency is present in the audited repository itself. The risk arises because the documented command delegates code execution and global installation to unpinned third-party supply-chain components.

Attack Path

  1. An attacker compromises the npm package resolved as skills, its maintainer account, or the mutable upstream Skill source.
  2. A user follows the README installation command.
  3. npx retrieves and executes the current package version rather than an audited, immutable version.
  4. The compromised CLI or upstream source executes with the invoking user's permissions.
  5. The installer writes a modified Skill into the global installation scope.
  6. The altered Skill may subsequently run whenever matching Agent requests activate it.

Impact Assessment

Exploitation could execute code with the permissions of the user running npx. Depending on the installer and host configuration, an attacker could modify user files, read credentials available to that process, make network requests, or install a malicious global Skill that affects later Agent sessions.

The command does not inherently provide root privileges, but its global scope broadens the affected Agent environment and allows a compromised ...[truncated 54 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove or disable the command until the referenced public source is available and independently reviewed.
  2. Pin the npx installer package to a specific reviewed version, for example by using an explicit version rather than the latest registry resolution.
  3. Pin the installed Skill to an immutable release, commit hash, signed tag, or content digest.
  4. Publish checksums or signatures and require verification before installation.
  5. Prefer a local or user-scoped installation over global installation unless global scope is operationally necessary.
  6. Document the exact source repository and release artifact so users can inspect what will execute.
  7. Use package-lock or equivalent integrity metadata for any future third-party dependencies.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (35)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents an end-user restaurant recommendation and local dining memory skill. The supplied code does not implement search, recommendations, taste/budget/occasion handling, visit recording, or memory updates. Instead, it only inspects environment variables for Amap and Serper keys, checks Python version support, and outputs a setup report. While Amap and Serper are mentioned in the description, this script’s primary purpose is operational diagnostics, which is materially different from the declared user-facing functionality.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

The code is restaurant-search related, so it overlaps at a high level with the declared domain. However, the implemented behavior is materially narrower and different from the description. This script is a CLI wrapper around search_fancard for a 'hidden-menu' search, taking only location, city, and budget inputs and returning up to three results. The declared skill promises a personalized restaurant recommender with local dining memory, visit logging, taste-profile updates, and map-provider selection logic. None of those capabilities are visible in this code chunk. Because the actual code supports a different, narrower search use case and lacks several core declared behaviors, this is a description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The supplied code is focused on local persistence and analysis of restaurant preference data: adding/removing/listing restaurants, recording experiences, computing liked/disliked tags, storing city/area info, tracking pending feedback, exporting data, and resetting the profile. This partially aligns with the memory/profile portion of the description, especially the claim that memory is limited to local restaurant preferences and feedback. However, the primary declared purpose emphasizes a restaurant finder that searches external map services and returns recommendations based on location, budget, occasion, and party size. None of that search or recommendation behavior appears in this code chunk. Instead, this chunk is a standalone profile-management script with several undeclared maintenance capabilities (export/reset/check/count/pending tracking). Therefore the description does not accurately represent what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a full restaurant-finder skill that searches external map services and returns recommendations. This code chunk does something materially different: it prepares contextual prompt text for another LLM component and manages local memory/history related to dining scenes and companions. While the local memory aspect is broadly consistent with the description’s mention of local dining memory, the core advertised capabilities—searching Amap/Google Maps, finding nearby restaurants, and producing 2+1 recommendations—are absent. Therefore the description overstates and misrepresents the behavior of this supplied code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The declared description presents a broader restaurant-finder skill with personalization, local memory, visit recording, and specific map providers by region. The actual code only implements a narrow search component: it constructs a Serper query restricted to dianping.com, filters likely restaurant pages, and parses restaurant metadata from search snippets. While this is related to restaurant discovery, the implementation materially differs from the declared primary behavior and resources. Most notably, it does not use Amap or Google Maps as described, and it does not implement memory or personalized recommendation features.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

The code is clearly related to restaurant recommendation and does use local dining preference memory for personalization, so the general domain matches. However, the declared description specifically says the skill searches Amap in mainland China and Google Maps via Serper elsewhere, while the code actually performs dual-source search using Dianping and Xiaohongshu. That is a material resource/behavior difference. Additionally, the description says the skill can record a restaurant visit and update a local taste profile, but this code only loads preferences from a local JSON file and never writes or updates memory. The 2+1 recommendation behavior is implemented, but the concrete data sources and memory-update capability do not match the declaration, so this should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The description and code are related at a high level—both concern restaurant discovery, especially global/overseas search—but they do not align closely enough. The code’s actual scope is a global search aggregator that searches multiple public websites via Serper and extracts restaurant metadata. In contrast, the declared description promises a broader personalized assistant with local dining memory, restaurant-visit recording, taste-profile updates, and structured 2+1 recommendations based on several user factors. None of that memory or personalization behavior appears in this code chunk. Additionally, the description says overseas search uses Google Maps via Serper, but the code also searches Yelp, Reddit, TripAdvisor, and optionally Xiaohongshu, which are materially undeclared external resources. Therefore this is a meaningful description-behavior mismatch, even though the domain (restaurant finding) is consistent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

There is partial alignment: the code clearly supports restaurant discovery and uses Amap for China and Serper/Google Maps for overseas, which matches the core finder description. However, the implementation materially expands behavior beyond the declared description by adding optional Baidu Maps search/merging in China and social-media cross-verification using Serper web search against Xiaohongshu. Those are external-resource capabilities not mentioned in the declared purpose. In addition, the code includes a distinct 'fancard' recommendation/filter mode with blacklist, budget, and sentiment-based blurbs that is not reflected in the description. Finally, a notable part of the declared purpose—recording restaurant visits and updating a local taste profile/memory—is absent from this code chunk. Because the actual code both adds undeclared capabilities and omits a declared one, this is a description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

The declared description presents the skill as a restaurant recommendation assistant driven by map providers (Amap/Google Maps via Serper) plus local preference memory and visit logging. The supplied code chunk instead implements Xiaohongshu-specific web search using Serper (site:xiaohongshu.com ... 探店), then parses note titles/snippets to extract restaurant mentions, price, and coarse sentiment. This is a materially different behavior and uses a different data source than declared. While Xiaohongshu searching could be a supporting signal for restaurant discovery, the description does not mention social-media scraping/search or sentiment analysis, and this chunk does not show the core declared capabilities like personalized recommendation logic, map-based nearby search, or local memory updates.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The guide instructs storing a persistent user.locale with categories including overseas-chinese, which is an ethnicity-linked classification. Persisting sensitive or quasi-sensitive demographic inference without clear necessity, explicit user consent, and retention safeguards creates privacy risk and can enable profiling beyond what is needed for restaurant recommendations.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file says the skill starts when users say phrases like "找餐厅", "吃什么", or "附近有什么好吃的". These are common conversational phrases and the guide does not provide clear scope limits or negative examples, so the skill could be invoked unintentionally during ordinary chat.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The guide allows activation on broad phrases such as "和她吃饭" and "两个人的饭" as well as "等", which leaves the trigger set open-ended. This makes it unclear when the special mode should activate versus when the user is merely describing a dining situation.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding

The README instructs users to install and execute a package via npx skills add oakcoderx/nomtiq -g without pinning an exact version or immutable source reference. This can expose installers to supply-chain risk if the skills package or resolution path changes, is typosquatted, or is compromised, and README-driven install commands are especially sensitive because users tend to copy/paste them verbatim.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill declares capabilities that require environment access, local file reads/writes, and outbound network calls, but it does not define an explicit tool scope such as permissions or allowed-tools. This creates an authorization ambiguity where the runtime may grant broader access than reviewers or users expect, increasing the risk of unintended secret access, local data modification, or external data exfiltration.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

python3 {baseDir}/scripts/doctor.py

text

Never ask the user to paste an API key into chat, a command argument, a skill file, or a log.

## Search routing

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The natural-language instructions, prompts, help text, and generated interaction content are all hard-coded in Chinese, including the guided conversation steps and output prompts. This can violate language/locale policy when no user opt-in or explicit region-specific justification is provided.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script persists restaurant preferences, likes/dislikes, locations, and inferred taste-profile data to a local JSON file without any disclosure, consent check, retention policy, or access control in this code path. Even though this is not remote code execution, it creates a privacy/security risk because sensitive behavioral profile data can be stored indefinitely and exposed to other local users, backups, logs, or later components that read the file.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The manifest says memory is limited to local restaurant preferences and feedback, but this file persists additional user profile state such as onboarding status, city/areas, hidden-menu unlock state, and later pending recommendation tracking. Those are related to the product, but they go beyond a narrow reading of storing only restaurant preferences and visit feedback.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The reset command deletes the entire profile file immediately with no confirmation, backup, or undo path. In a CLI or agent-integrated context, an accidental invocation or misuse can irreversibly erase all stored preference and visit history, causing denial of service against the user's local data.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest describes recording restaurant visits and updating a local taste profile, but these commands add, list, and clear a separate 'pending_feedback' queue for prior recommendations. Tracking recommendation reminders and elapsed time since recommendation is a distinct retained-memory behavior not reflected in the stated description.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module docstring, command examples, help text, and user-facing outputs are all written in Chinese, which effectively forces a specific language for interaction. The file does not provide any user opt-in, alternative locale, or explanation that this is intentionally limited to a Chinese-speaking or region-specific environment.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring, argument descriptions, and runtime output are all written in Chinese, which effectively forces a specific language for users of the skill. Under the policy, a fixed language without user opt-in or a clearly documented region-specific justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest says this skill searches Amap in mainland China and Google Maps via Serper elsewhere, but this script actually performs phase-1 search through Dianping and phase-2 cross-verification through Xiaohongshu. That is a substantive behavior difference in data sources and recommendation methodology, not just an implementation detail.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The natural-language description states the tool is for '海外用户或海外华人场景' and uses only Chinese-language user-facing text. This creates a locale/language constraint in the skill definition without documenting user choice or a justified compliance reason.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The module docstring states that only AMAP_WEBSERVICE_KEY/AMAP_KEY and optional AMAP_WEBSERVICE_SECRET are read from environment variables. Later, the code also reads BMAP_KEY for optional Baidu Maps access, which directly contradicts the stated environment-variable limitation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.