Skill flagged — suspicious patterns detected

ClawHub Security flagged this skill as suspicious. Review the scan results before using.

Websearch

v0.1.1

Perform web searches using various search engines and APIs.

0· 556·1 current·1 all-time
byRory@roryyu

Install

OpenClaw Prompt Flow

Install with OpenClaw

Best for remote or guided setup. Copy the exact prompt, then paste it into OpenClaw for roryyu/websearch-free-skill.

Previewing Install & Setup.
Prompt PreviewInstall & Setup
Install the skill "Websearch" (roryyu/websearch-free-skill) from ClawHub.
Skill page: https://clawhub.ai/roryyu/websearch-free-skill
Keep the work scoped to this skill only.
After install, inspect the skill metadata and help me finish setup.
Required binaries: node, npm
Use only the metadata you can verify from ClawHub; do not invent missing requirements.
Ask before making any broader environment changes.

Command Line

CLI Commands

Use the direct CLI path if you want to install manually and keep every step visible.

OpenClaw CLI

Bare skill slug

openclaw skills install websearch-free-skill

ClawHub CLI

Package manager switcher

npx clawhub@latest install websearch-free-skill
Security Scan
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Suspicious
medium confidence
!
Purpose & Capability
Name/description match the claimed capability (web search and page reading) and the required binaries (node, npm) are consistent with a Node.js implementation — that part is coherent. However, the skill documentation lists runtime scripts (search.js, exasearch.js), a package.json/dependencies (axios, mcporter) and an npm install step, but the asset manifest contains only README.md and SKILL.md (no code files, no package.json). Requesting Node/npm without shipping the code or a package.json is disproportionate and incoherent.
!
Instruction Scope
SKILL.md instructs the agent/operator to run node ./search.js and node ./exasearch.js to fetch arbitrary web URLs and query a search provider (Jina Reader API and Exa via mcporter). Fetching external URLs is expected for a websearch skill, but the instructions also direct automatic dependency installation via npm and call out the third-party 'mcporter' integration. Because the actual script files are not present in the package, the instructions are incomplete and grant broad discretion (install and run arbitrary npm packages) that is outside the provided artifact.
!
Install Mechanism
No install spec is provided in the registry (instruction-only), which is the lowest-risk pattern — but SKILL.md explicitly tells users to run 'npm install' and lists dependencies. That mismatch is concerning: the skill asks to install packages at runtime even though no package.json or code is included. Installing arbitrary npm dependencies (including 'mcporter') without a vetted source increases risk.
Credentials
The skill declares no required environment variables, no credentials, and no config paths. For a websearch/URL-reading skill this is proportionate. There is no evidence the skill requests unrelated secrets.
Persistence & Privilege
Flags show always: false and normal autonomous invocation settings. The skill does not request permanent presence or elevated agent-wide privileges.
What to consider before installing
This package's documentation describes Node scripts and npm dependencies (axios, mcporter) and instructs you to run 'npm install' and 'node search.js', but the registry entry only contains SKILL.md and README.md — the actual code and package.json are missing. Before installing or running anything: (1) ask the publisher for the missing source files or a link to the project repo/homepage and verify package.json and code; (2) inspect package.json and node modules for unfamiliar or high-risk packages (mcporter is uncommon); (3) avoid running npm install or executing downloaded scripts until you've reviewed them; (4) if you must test, do so in a strict sandbox or ephemeral environment with no sensitive data or credentials available. The mismatch between claimed behavior and the provided files is the reason this is flagged as suspicious.

Like a lobster shell, security has layers — review code before you run it.

Runtime requirements

🔍 Clawdis
Binsnode, npm
latestvk979xwdk5afvfaxb5af05ehwm1835rq1
556downloads
0stars
2versions
Updated 14h ago
v0.1.1
MIT-0

Web Search Skill / 网络搜索技能

Perform web searches using various search engines and APIs. This skill provides access to search functionality without requiring API keys for basic usage.

使用各种搜索引擎和API进行网络搜索。此技能提供搜索功能访问,无需API密钥即可进行基本操作。

Features / 功能特性

  • URL Content Extraction: Read and extract content from any web page URL URL内容提取: 从任意网页URL读取和提取内容
  • Keyword Search: Search for specific keywords and return specified number of results 关键词搜索: 搜索特定关键词并返回指定数量的结果
  • Dependency Management: Automatic dependency installation via npm 依赖管理: 通过npm自动安装依赖项

Basic Usage / 基础用法

Read content from a specific URL:

从特定URL读取内容:

node ./search.js <url> [previewLength]

Parameters / 参数:

  • url: The URL to read (required) 要读取的URL(必需)
  • previewLength: Number of characters to preview (optional, default: 200, use 0 to disable preview) 预览字符数(可选,默认:200,使用0禁用预览)

Examples / 示例:

# Default preview (200 characters)
# 默认预览(200字符)
node ./search.js https://www.example.com

# Preview 500 characters
# 预览500字符
node ./search.js https://www.example.com 500

# No preview (show only metadata)
# 无预览(仅显示元数据)
node ./search.js https://www.example.com 0

Output Format / 输出格式:

  • Title / 标题
  • URL
  • Platform / 平台
  • Content length / 内容长度
  • Content preview / 内容预览(可选)

Advanced Usage / 高级用法

Search with specific keyword and result limit:

使用特定关键词和结果限制进行搜索:

node ./exasearch.js <keyword> [numResults]

Parameters / 参数:

  • keyword: Search query string (required) 搜索查询字符串(必需)
  • numResults: Number of results to return (optional, default: 10, max: 100) 返回结果数量(可选,默认:10,最大:100)

Examples / 示例:

# Basic search with default 10 results
# 默认10个结果的基础搜索
node ./exasearch.js "artificial intelligence"

# Search with 20 results
# 搜索20个结果
node ./exasearch.js "machine learning" 20

# Search with 50 results
# 搜索50个结果
node ./exasearch.js "deep learning" 50

Setup / 安装设置

First-time setup requires installing dependencies:

首次使用需要安装依赖:

Prerequisites / 前置要求:

  • Node.js v22 or higher / Node.js v22 或更高版本
  • npm or yarn
npm install

Dependencies / 依赖项:

  • axios: HTTP client for web requests HTTP客户端,用于网络请求
  • mcporter: Tool integration framework 工具集成框架

Error Handling / 错误处理

The scripts include comprehensive error handling for:

脚本包含全面的错误处理:

  • Missing required parameters / 缺少必需参数
  • Invalid parameter values / 无效参数值
  • Network connection errors / 网络连接错误
  • HTTP request failures / HTTP请求失败
  • Server timeout errors / 服务器超时错误

Technical Details / 技术细节

  • Backend / 后端: Jina Reader API (https://r.jina.ai)
  • Timeout / 超时: 15 seconds for web requests / 网络请求15秒
  • Output Format / 输出格式: JSON / Markdown
  • Search Provider / 搜索提供商: Exa API (via mcporter)

Logic Examples / 逻辑示例

ReadResult.js - Result Object Class

export class ReadResult {
  constructor(title, content, url, platform = "web") {
    this.title = title;
    this.content = content;
    this.url = url;
    this.platform = platform;
  }

  toDict() {
    return {
      title: this.title,
      content: this.content,
      url: this.url,
      platform: this.platform
    };
  }
}

search.js - URL Content Extraction

import axios from 'axios';
import { ReadResult } from './ReadResult.js';

class WebChannel {
  constructor() {
    this.JINA_URL = "https://r.jina.ai/";
  }

  async read(url) {
    try {
      const response = await axios.get(`${this.JINA_URL}${url}`, {
        headers: {
          'Accept': 'text/markdown'
        },
        timeout: 15000
      });

      const text = response.data;
      let title = url;
      const lines = text.split('\n');
      
      for (const line of lines) {
        const trimmedLine = line.trim();
        if (trimmedLine.startsWith('# ')) {
          title = trimmedLine.substring(2).trim();
          break;
        }
        if (trimmedLine.startsWith('Title:')) {
          title = trimmedLine.substring(6).trim();
          break;
        }
      }

      return new ReadResult(title, text, url, "web");

    } catch (error) {
      if (error.response) {
        throw new Error(`HTTP ${error.response.status}: ${error.response.statusText}`);
      } else if (error.request) {
        throw new Error('Network error: No response received');
      } else {
        throw new Error(`Request failed: ${error.message}`);
      }
    }
  }
}

async function main() {
  const url = process.argv[2];
  const previewLength = process.argv[3] ? parseInt(process.argv[3], 10) : 200;
  
  if (!url) {
    console.error('Usage: node search.js <url> [previewLength]');
    console.error('  url: The URL to read');
    console.error('  previewLength: Number of characters to preview (optional, default: 200)');
    process.exit(1);
  }

  if (isNaN(previewLength) || previewLength < 0) {
    console.error('Error: previewLength must be a non-negative integer');
    process.exit(1);
  }

  const webChannel = new WebChannel();
  
  try {
    console.log(`Reading: ${url}`);
    const result = await webChannel.read(url);
    
    console.log('\n=== Read Result ===');
    console.log(`Title: ${result.title}`);
    console.log(`URL: ${result.url}`);
    console.log(`Platform: ${result.platform}`);
    console.log(`Content length: ${result.content.length} characters`);
    
    if (previewLength > 0) {
      console.log(`\nFirst ${previewLength} characters of content:`);
      const preview = result.content.substring(0, previewLength);
      console.log(preview + (result.content.length > previewLength ? '...' : ''));
    }
    
  } catch (error) {
    console.error('Error reading web page:', error.message);
    process.exit(1);
  }
}

main();

exasearch.js - Keyword Search

import { callOnce } from "mcporter";

async function main() {
  const keyword = process.argv[2];
  const num = process.argv[3];

  if (!keyword) {
    console.error('Error: Search keyword is required');
    console.error('Usage: node exasearch.js <keyword> [numResults]');
    process.exit(1);
  }

  const numResults = num ? parseInt(num, 10) : 10;

  if (isNaN(numResults) || numResults < 1) {
    console.error('Error: numResults must be a positive integer');
    process.exit(1);
  }

  if (numResults > 100) {
    console.error('Error: numResults cannot exceed 100');
    process.exit(1);
  }

  try {
    console.log(`Searching for: ${keyword}`);
    console.log(`Number of results: ${numResults}`);
    
    const result = await callOnce({
      server: "exa",
      toolName: "web_search_exa",
      args: { query: keyword, numResults: numResults },
    });

    console.log('\n=== Search Results ===');
    console.log(JSON.stringify(result, null, 2));
    
  } catch (error) {
    console.error('Error during search:', error.message);
    
    if (error.response) {
      console.error(`HTTP ${error.response.status}: ${error.response.statusText}`);
    } else if (error.request) {
      console.error('Network error: No response received from server');
    } else if (error.code === 'ECONNREFUSED') {
      console.error('Connection refused: Unable to reach the search server');
    } else if (error.code === 'ETIMEDOUT') {
      console.error('Request timeout: Server took too long to respond');
    }
    
    process.exit(1);
  }
}

main();

Comments

Loading comments...