Back to skill

Security audit

PharmaAI

Security checks for vulnerabilities and agentic risk

Overview

This skill needs Review because it advertises pharmaceutical assessments that the inspected code does not actually compute, including hard-coded ADMET and Lipinski results.

Install only for experimentation or development review. Do not rely on this skill for real drug-safety, medical, regulatory, or compound-prioritization decisions unless ADMET, Lipinski, model provenance, and validation warnings are fixed. Review dependency locking, model-file trust, and avoid pasting real ClawHub tokens into shell commands or persistent files unless you understand the exposure risk.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
src/python-bridge/index.ts:14
Finding
Path Traversal Enables Execution of Arbitrary Local Python Scripts<![CDATA[ ## Vulnerability Details **File Location**: `src/python-bridge/index.ts:14-22` **Vulnerability Type**: Path traversal leading to local code execution **Risk Level**: High ### Vulnerable Code ```typescript export async function callPython( scriptName: string, input: PythonInput ): Promise<PythonOutput> { return new Promise((resolve, reject) => { const scriptPath = path.join(PYTHON_CORE_DIR, `${scriptName}.py`); const python = spawn('python3', [scriptPath, JSON.stringify(input)]); ``` ### Technical Analysis The exported `callPython` function accepts an unrestricted `scriptName` and constructs an executable path by joining that value with `PYTHON_CORE_DIR`. The value is not checked against an allowlist and the normalized path is not verified to remain inside the intended directory. Although `spawn` is used without a shell, which prevents conventional shell metacharacter injection, directory traversal remains possible. A value containing components such as `../../` can resolve to a Python file outside `python-core`. The resulting path is passed directly to the Python interpreter. The automatically appended `.py` suffix limits the target to Python files, but it does not prevent traversal or execution of attacker-selected scripts. ### Attack Path 1. An attacker obtains access to the exported `callPython` bridge, such as through application code that exposes it or permits arbitrary bridge calls. 2. The attacker supplies a traversal value such as `../../../../tmp/payload` as `scriptName`. 3. `path.join` normalizes the path outside `PYTHON_CORE_DIR`, resulting in a target such as `/tmp/payload.py`. 4. If that Python file exists and is readable, `spawn('python3', ...)` executes it. 5. The script runs with the operating-system identity and permissions of the Node.js process. Exploitation requires the attacker to control the `scriptName` argument and identify or place an executable Python file on the local filesystem. ### Impact Asses ...[truncated 423 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not expose a generic script execution function as part of the public bridge interface. - Replace caller-provided script names with a fixed allowlist mapping: ```typescript const SCRIPTS = { predict: path.join(PYTHON_CORE_DIR, 'predict.py') } as const; type ScriptName = keyof typeof SCRIPTS; ``` - Resolve and validate the final path before execution: ```typescript const coreDirectory = path.resolve(PYTHON_CORE_DIR); const scriptPath = path.resolve(coreDirectory, `${scriptName}.py`); if ( !scriptPath.startsWith(coreDirectory + path.sep) || !/^[a-zA-Z0-9_-]+$/.test(scriptName) ) { throw new Error('Invalid Python script name'); } ``` - Prefer dedicated functions that always invoke a hardcoded script rather than accepting any script name. - Run the subprocess as a restricted service account with minimal filesystem and network permissions. - Add tests covering `../`, absolute-path-like input, encoded traversal attempts, and unsupported script names. ]]>

other

Error
Location
src/commands/predict.ts:17
Finding
Fabricated ADMET and Lipinski Results Are Returned as Pharmaceutical Assessments<![CDATA[ ## Vulnerability Details **File Location**: `src/commands/predict.ts:17-24` **Vulnerability Type**: Misleading safety-critical output **Risk Level**: High ### Vulnerable Code The single-molecule path returns fixed values: ```typescript return { smiles: result.smiles, name: undefined, toxicity: result.toxicity, admet: { solubility: 'Medium', // Simplified; should actually come from Python metabolicStability: 'Medium', cypInhibition: 'Low' }, overallScore: calculateOverallScore(result.toxicity), lipinskiPass: true // Simplified }; ``` The batch path repeats the same behavior at `src/commands/predict.ts:34-43`: ```typescript return results.map((r: any) => ({ smiles: r.smiles, toxicity: r.toxicity, admet: { solubility: 'Medium', metabolicStability: 'Medium', cypInhibition: 'Low' }, overallScore: calculateOverallScore(r.toxicity), lipinskiPass: true })); ``` ### Technical Analysis ADMET properties and Lipinski-rule compliance are presented in the returned `MoleculePrediction` object even though they are not calculated from the submitted molecule. Every molecule receives identical ADMET values, and every molecule is marked as passing Lipinski rules. This behavior conflicts with the documented functionality and creates an integrity problem in a safety-sensitive pharmaceutical context. Type-safe response fields make these constants appear indistinguishable from genuine model or descriptor output. There is also no warning or metadata indicating that these fields are placeholders. ### Attack Path 1. A caller submits any valid molecule to `predictMolecule` or a list to `batchPredict`. 2. The Python bridge produces toxicity output. 3. The TypeScript wrapper adds fixed ADMET values and sets `lipinskiPass` to `true`, regardless of molecular properties. 4. The caller receives the combined object as a prediction result. 5. Downstream screening or decision logic may treat the fabricated values as calculated e ...[truncated 608 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove ADMET and Lipinski fields until they are genuinely implemented, or return an explicit state such as `null`, `notCalculated`, or `unsupported`. - Calculate Lipinski compliance from validated molecular descriptors rather than returning a constant. - Implement and validate the advertised ADMET models before exposing ADMET output. - Add provenance metadata identifying the model, model version, calibration data, and calculation method for each returned property. - Clearly distinguish experimental placeholders from validated predictions in both types and documentation. - Add automated tests demonstrating that chemically different molecules can produce different ADMET and Lipinski results. - Reject incomplete model output instead of silently substituting favorable defaults. - Include an explicit warning that computational predictions are not substitutes for laboratory or clinical safety evaluation. ]]>

T08 · Insecure Dependencies

Warning
Location
python-core/requirements.txt:1
Finding
Unbounded Dependencies and Missing Lockfiles Create Supply-Chain Risk<![CDATA[ ## Vulnerability Details **File Location**: `python-core/requirements.txt:1-4` **Vulnerability Type**: Non-reproducible dependency resolution **Risk Level**: Medium ### Vulnerable Code ```text rdkit>=2023.0.0 scikit-learn>=1.3.0 numpy>=1.24.0 joblib>=1.3.0 ``` The Node.js manifest also uses broad compatible ranges at `package.json:23-30`: ```json "dependencies": { "@openclaw/skill-sdk": "^1.0.0" }, "devDependencies": { "@types/node": "^20.0.0", "typescript": "^5.0.0", "ts-node": "^10.9.0", "jest": "^29.0.0", "@types/jest": "^29.0.0" } ``` No dependency lockfile or Python hash-locked requirements file was present in the audited project. ### Technical Analysis The Python dependencies have no upper bounds, while the Node.js dependencies use caret ranges. Consequently, two installations of the same source revision can resolve to different dependency versions. The absence of lockfiles and artifact hashes prevents consumers from verifying the exact dependency graph expected by the project. If an upstream package account, release process, or package artifact is compromised, a later installation could select the affected version without any source-code modification in this project. No malicious dependency was identified in the supplied files. The confirmed defect is the mutable, non-reproducible installation policy rather than evidence that a listed package is currently malicious. ### Attack Path 1. A user follows the documented installation process and runs `npm install` and `pip install -r python-core/requirements.txt`. 2. The package managers resolve versions at installation time using broad version constraints. 3. A newer compatible or otherwise resolution-eligible release is selected. 4. If that release or its distribution artifact has been compromised, its installation or runtime code executes in the consumer environment. 5. The compromised dependency receives the privileges available to the installation or application process. T ...[truncated 638 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin production dependencies to reviewed, exact versions. - Generate and commit a Node.js lockfile using the selected package manager. - Use a Python locking workflow such as `pip-tools`, Poetry, or an equivalent reproducible resolver. - Require hashes for Python artifacts, for example through a generated requirements file installed with `pip --require-hashes`. - Review transitive dependencies and run dependency vulnerability scanning in continuous integration. - Use automated dependency update pull requests so version changes are explicit and reviewable. - Build from trusted registries and consider registry allowlists or an internal artifact mirror. - Install dependencies as a non-privileged user and avoid running package managers with administrative privileges. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (38)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The finding indicates placeholder or hardcoded outputs are presented as real analysis, such as fixed ADMET values and unconditional Lipinski passes, plus inconsistent output fields. This is dangerous because it can cause users to treat fabricated or nonfunctional results as scientifically grounded assessments in a high-stakes biomedical workflow.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The finding indicates placeholder or hardcoded outputs are presented as real analysis, such as fixed ADMET values and unconditional Lipinski passes, plus inconsistent output fields. This is dangerous because it can cause users to treat fabricated or nonfunctional results as scientifically grounded assessments in a high-stakes biomedical workflow.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
This is a direct implementation-to-claim mismatch: the skill exposes ADMET evaluation and Lipinski pass/fail as if they were genuine analytical outputs, but the code never performs those calculations. In a drug-discovery assistant, false scientific outputs are especially dangerous because users may rely on them for compound triage, safety assessment, or experimental planning.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The batch interface presents itself as complete molecular analysis while only performing toxicity prediction and inventing the remaining fields. Because batch processing is likely used for library-scale candidate selection, the misleading output can amplify bad decisions across many compounds and undermine scientific validity.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The documentation instructs users to pass long-lived API tokens directly on the command line and to write them to files using shell commands, but it does not warn that command-line arguments may be exposed via shell history, process listings, logs, or terminal recording. In a headless/server context, this increases the chance of accidental credential disclosure and subsequent unauthorized access to the ClawHub account.

Session Persistence

Medium
Category
Rogue Agent
Content
创建配置文件:
```bash
mkdir -p ~/.config/clawhub
echo "ch_abc123def456" > ~/.config/clawhub/token
chmod 600 ~/.config/clawhub/token
```
Confidence
89% confidence
Finding
The documentation recommends persisting an API token in a local config file, creating a durable credential on disk. Even with mode 600, persistent storage raises the risk of secret recovery from backups, compromised user accounts, misconfigured home directory sync, or accidental inclusion in support bundles and scripts.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
mkdir -p ~/.config/clawhub
echo "ch_abc123def456" > ~/.config/clawhub/token
chmod 600 ~/.config/clawhub/token
```

## 📋 完整发布流程(无浏览器环境)
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
或者使用文本浏览器(部分OAuth支持):
```bash
# 安装 lynx 或 w3m
sudo apt-get install lynx

# 尝试使用文本浏览器
lynx https://clawhub.com
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The primary skill description is presented in Chinese only, with no indication that users can choose another language or that the skill is intentionally limited to a Chinese-speaking audience. This creates a natural-language policy concern because it implicitly enforces a specific language without user opt-in or documented justification.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill presents toxicity and ADMET outputs, including an overall label of 'Safe', without prominent warnings that results are only advisory and unsuitable for medical, regulatory, or real-world safety decisions. In a pharmaceutical context, that framing can directly encourage overreliance on imperfect models and understate serious toxicology uncertainty.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The package description is entirely in Chinese and presents the skill as a general AI assistant, with no indication that language is configurable or limited to a Chinese-speaking audience. For a generally scoped skill, this can violate a language/locale policy requiring user choice or explicit justification for locale restrictions.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
This file contains natural-language comments/docstrings and interface text in Chinese, including the module description and later user-visible messages, but does not indicate that the skill is region-specific or provide an opt-in language choice. That can violate language/locale policy for users who are not expecting a Chinese-only experience.

Insecure deserialization: joblib.load()

Medium
Category
Dangerous Code Execution
Content
"""加载模型(带缓存)"""
    if model_name not in _models:
        model_path = os.path.join(MODELS_DIR, f'{model_name}_model.pkl')
        _models[model_name] = joblib.load(model_path)
    return _models[model_name]

def calculate_features(smiles):
Confidence
95% confidence
Finding
`joblib.load()` deserializes pickle-based data, which can execute arbitrary code during loading if the model file is malicious or has been replaced. In this skill, model names are fixed, which reduces direct user control, but the risk remains significant because compromise of the model directory, package supply chain, or deployment artifact would turn model loading into code execution inside the Python process.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The manifest describes broader functionality including ADMET property evaluation and Lipinski rule validation, but the implemented actions in this file only expose single prediction, batch prediction, and screening based on hERG/hepatotoxicity/Ames toxicity outputs. Although descriptors relevant to Lipinski are computed internally, they are not returned or used to provide the claimed ADMET or rule-of-five assessment behavior.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The file returns hard-coded user-visible text such as 'Invalid SMILES', 'No input provided', and 'Unknown action' while the rest of the module is documented in Chinese. This mixed but fixed-language behavior provides no explicit language choice or justified locale constraint.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The function advertises molecule prediction results that include ADMET and Lipinski-related fields, but those values are hard-coded placeholders rather than computed outputs. In a pharmaceutical discovery context, fabricated safety and developability data can mislead downstream research, screening, or prioritization decisions, creating a serious integrity and safety risk.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The batch API similarly returns fixed ADMET and Lipinski values for every molecule, which falsely implies those properties were assessed per compound. In bulk screening workflows, this can systematically contaminate large result sets and lead users to trust nonexistent analyses at scale.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This function returns all user-facing result text in Chinese string literals, and the file contains no indication that the skill is region-specific or that users can choose their preferred language. That creates a language/locale policy issue under the natural-language policy rules because the skill effectively forces a specific language without opt-in.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The file's natural-language descriptions and user-facing CLI help strings are written in Chinese only, with no indication that users can choose another language or locale. This can violate language/locale policy requirements when a skill is expected to be usable without forcing a specific language.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The command-line interface prints usage guidance such as command descriptions only in Chinese, and the file does not document that the tool is region- or language-specific. Forcing one language in user-facing operational text without opt-in can be a policy violation.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This code launches a Python subprocess and passes serialized input data to it, which is a safety-relevant operation under the code-file warning criteria. Although the function has internal comments, there is no confirmation prompt, user-facing log/print, or other visible disclosure in this file that informs a user their data is being sent to a child process.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
The skill content forces a specific language for all instructions and user-facing guidance, which can violate language/locale policy when no opt-in or alternative is provided. There is no indication that this is a China-specific or Chinese-only skill, nor any note offering another language version.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
This markdown file contains user-facing instructions exclusively in Chinese, including the title, steps, and guidance, with no indication that other languages are available. Under the policy rule for language or locale constraints, this can be a violation because it forces a specific language without user opt-in or documented justification.

Natural-Language Policy Violations

Low
Confidence
86% confidence
Finding
SQP-3 applies to all file types and includes language or locale policy violations. Most user-facing descriptive content is written in Chinese, and the file does not indicate that other languages are supported or that the Chinese-only presentation is an intentional, justified regional constraint.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"author": "PharmaAI Team",
  "license": "MIT",
  "dependencies": {
    "@openclaw/skill-sdk": "^1.0.0"
  },
  "devDependencies": {
    "@types/node": "^20.0.0",
Confidence
90% confidence
Finding
Using a caret range for a production dependency allows automatic installation of newer minor/patch releases, increasing supply-chain risk if the upstream package is compromised or ships a breaking or malicious update. Because this is the runtime SDK for the skill, compromise here could directly affect execution of the packaged agent.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
src/python-bridge/index.ts:22