Back to skill

Security audit

PharmaClaw Chemistry Query

Security checks for vulnerabilities and agentic risk

Overview

This is mostly a real chemistry toolkit, but it needs Review because one script silently loads unaudited code from a neighboring folder and some file path options can access or overwrite arbitrary files the agent can reach.

Install only if you are comfortable with public chemistry API lookups and a runtime OPSIN JAR download. Run it in an isolated workspace, avoid using scripts/chain_entry.py until the hidden lab_hook import is removed or explicitly trusted, and do not provide sensitive local file paths to input_file or output options.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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
Findings (3)

T07 · Tool Hijacking and Spoofing

Error
Location
scripts/chain_entry.py:11
Finding

External Dashboard Hook Permits Local Python Module Hijacking

Content
View full analysis

Vulnerability Details

File Location: scripts/chain_entry.py:11-16
Vulnerability Type: Untrusted external module loading
Risk Level: High

python
# === PharmaLab Dashboard Hook ===
sys.path.insert(0, os.path.join(script_dir, '..', '..', 'pharmaclaw-lab-ui', 'scripts'))
try:
    from lab_hook import lab_update
except ImportError:
    def lab_update(*a, **kw): pass

Technical Analysis

The script prepends a directory outside the audited project to Python's module search path and then imports lab_hook from that location. Python executes all module-level code when a module is imported.

The imported module is not included in the audited project, is not declared as a trusted dependency, and is not verified before execution. Consequently, an attacker who can create or modify pharmaclaw-lab-ui/scripts/lab_hook.py can cause arbitrary Python code to run whenever chain_entry.py starts.

The use of sys.path.insert(0, ...) gives this external directory priority over normal module locations, increasing the risk of module spoofing. Catching ImportError does not mitigate the issue because malicious module-level code executes before the import completes.

Attack Path

  1. An attacker gains the ability to create or modify the sibling path pharmaclaw-lab-ui/scripts.
  2. The attacker places a malicious file named lab_hook.py in that directory.
  3. A user or Agent invokes scripts/chain_entry.py for a normal chemistry operation.
  4. The script places the attacker-controlled directory at the beginning of sys.path.
  5. Python imports the malicious lab_hook and executes its module-level code.
  6. The payload runs with the same operating-system privileges, filesystem access, environment variables, and network access as the Agent process.

Impact Assessment

Successful exploitation provides arbitrary code execution under the account running the Skill. The attacker could read or modify files a ...[truncated 466 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove the dynamic sys.path modification and external dashboard hook if it is not essential to chemistry processing.
  2. If the integration is required, distribute it as an explicit, reviewed, and version-pinned package rather than importing from a relative sibling directory.
  3. Import the dependency through the normal Python package mechanism without placing writable directories at the beginning of sys.path.
  4. Verify the origin and integrity of any optional plugin before loading it.
  5. Disable the integration by default and require an explicit trusted configuration setting to enable it.
  6. Run the Skill under a dedicated least-privileged account and ensure project-adjacent directories are not writable by untrusted users.
  7. Document the external hook and its security boundary in SKILL.md.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/opsin_name_to_smiles.py:42
Finding

OPSIN Conversion Supports Unrestricted Arbitrary File Writes

Content
View full analysis

Vulnerability Details

File Location: scripts/opsin_name_to_smiles.py:42-59
Vulnerability Type: User-controlled file write path
Risk Level: Medium

python
parser = argparse.ArgumentParser(description="OPSIN IUPAC name to SMILES")
parser.add_argument("--name", required=True, help="IUPAC/systematic name")
parser.add_argument("--output", help="Output SMILES file")
args = parser.parse_args()

jar_path = os.path.join(os.path.dirname(__file__), "opsin.jar")
ensure_opsin(jar_path)

cmd = ["java", "-jar", jar_path, "--stdin", "--output", "smiles"]
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
stdout, stderr = proc.communicate(input=args.name)
if proc.returncode != 0:
    print(json.dumps({"error": stderr.strip()}), file=sys.stderr)
    sys.exit(1)

smiles = stdout.strip()
result = {"name": args.name, "smiles": smiles}
print(json.dumps(result))
if args.output:
    with open(args.output, 'w') as f:
        f.write(smiles)

Technical Analysis

The --output argument is used directly in open(..., 'w') without path canonicalization, directory confinement, traversal prevention, symlink checks, or overwrite protection.

Both absolute paths and relative traversal paths are accepted. Opening an existing file in write mode truncates it before writing the OPSIN-generated SMILES value. The process can therefore create or overwrite any file writable by the account running the Skill.

The content written is constrained to OPSIN output, which limits direct payload control. Nevertheless, destructive file truncation and corruption remain possible, and specially selected chemical names may produce attacker-influenced text suitable for some data-file contexts.

Attack Path

  1. An attacker persuades an Agent or user to perform OPSIN conversion with a crafted --output value.
  2. The value identifies an absolute path, a traversal pa ...[truncated 740 chars]
Remediation
View remediation

Remediation Suggestions

  1. Restrict outputs to a dedicated application-controlled directory.
  2. Resolve both the output path and allowed directory with Path.resolve() or os.path.realpath(), then verify that the resolved output remains beneath the allowed directory.
  3. Reject absolute paths, parent-directory traversal, null bytes, and unsupported extensions.
  4. Check every existing path component for symlinks or securely open files relative to a trusted directory using platform-supported directory file descriptors.
  5. Use exclusive creation mode when overwriting is not required. If replacement is required, obtain explicit confirmation and perform an atomic replacement.
  6. Generate server-side filenames rather than accepting unrestricted paths from callers.
  7. Apply the same centralized path-validation function used by other project scripts.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/advanced_chem.py:503
Finding

Chemical-Space Input Accepts Unrestricted Filesystem Paths

Content
View full analysis

Vulnerability Details

File Location: scripts/advanced_chem.py:503-510
Vulnerability Type: Arbitrary local file read
Risk Level: Medium

python
if input_file:
    input_file = _sanitize_input(input_file, "input_file", max_len=500)
    if not os.path.exists(input_file):
        raise ValueError(f"File not found: {input_file}")
    with open(input_file) as f:
        for line in f:
            line = line.strip()
            if line and not line.startswith('#'):
                smiles_list.append(line.split()[0])  # first column

Technical Analysis

The input_file value is passed through _sanitize_input, but that function only validates the data type, maximum length, and absence of null bytes. It does not reject absolute paths, prevent parent-directory traversal, confine access to an approved workspace, or prevent symlink escapes.

The script subsequently checks the path and opens it using the privileges of the Agent process. This permits callers to direct the Skill to any readable local file.

Disclosure is format-dependent: each non-comment line is reduced to its first whitespace-delimited token, and only values accepted as valid SMILES are retained in later processing. Even with this limitation, the interface provides an unauthorized file-access and existence-probing primitive. Files containing SMILES-like strings may have their content reflected in generated coordinates and results.

Attack Path

  1. An attacker supplies --action chemspace with a crafted --input_file path.
  2. The path identifies an absolute file, uses traversal to leave the intended workspace, or references a symlink.
  3. The script confirms whether the file exists and opens it under the Agent's permissions.
  4. The script parses the first token from each line.
  5. Tokens accepted as SMILES are returned in the chemical-space results and represented in the generated plot.
  6. Differences between file-not-found, ...[truncated 620 chars]
Remediation
View remediation

Remediation Suggestions

  1. Restrict input files to a dedicated, explicitly configured data directory.
  2. Canonicalize the requested path and allowed root with Path.resolve(strict=True), then verify that the file is a descendant of the allowed root.
  3. Reject absolute paths and traversal components when callers are expected to provide only workspace-relative names.
  4. Prevent symlink escapes by validating the fully resolved path and, where possible, opening files relative to a trusted directory descriptor.
  5. Require a regular file with an approved extension and enforce a maximum file size and maximum line count.
  6. Avoid exposing raw filesystem errors or path details to untrusted callers.
  7. If external files are a legitimate requirement, require explicit user authorization and expose them through a controlled upload or file-selection mechanism rather than an arbitrary path argument.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (50)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

This mismatch appears to hide broader CLI actions and delegated execution paths, including external script resolution and undeclared analysis modes. In a code skill, undeclared execution pathways matter because they may bypass security review assumptions and lead to unexpected file, subprocess, or network operations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

This mismatch appears to hide broader CLI actions and delegated execution paths, including external script resolution and undeclared analysis modes. In a code skill, undeclared execution pathways matter because they may bypass security review assumptions and lead to unexpected file, subprocess, or network operations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This mismatch appears to hide broader CLI actions and delegated execution paths, including external script resolution and undeclared analysis modes. In a code skill, undeclared execution pathways matter because they may bypass security review assumptions and lead to unexpected file, subprocess, or network operations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This mismatch appears to hide broader CLI actions and delegated execution paths, including external script resolution and undeclared analysis modes. In a code skill, undeclared execution pathways matter because they may bypass security review assumptions and lead to unexpected file, subprocess, or network operations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

This mismatch appears to hide broader CLI actions and delegated execution paths, including external script resolution and undeclared analysis modes. In a code skill, undeclared execution pathways matter because they may bypass security review assumptions and lead to unexpected file, subprocess, or network operations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This mismatch appears to hide broader CLI actions and delegated execution paths, including external script resolution and undeclared analysis modes. In a code skill, undeclared execution pathways matter because they may bypass security review assumptions and lead to unexpected file, subprocess, or network operations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

This mismatch appears to hide broader CLI actions and delegated execution paths, including external script resolution and undeclared analysis modes. In a code skill, undeclared execution pathways matter because they may bypass security review assumptions and lead to unexpected file, subprocess, or network operations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

This mismatch appears to hide broader CLI actions and delegated execution paths, including external script resolution and undeclared analysis modes. In a code skill, undeclared execution pathways matter because they may bypass security review assumptions and lead to unexpected file, subprocess, or network operations.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/advanced_chem.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/advanced_chem.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/advanced_chem.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/advanced_chem.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/advanced_chem.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/advanced_chem.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/advanced_chem.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/advanced_chem.py`

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill declares capabilities that imply shell execution, network access, and file writes, but it does not define an explicit tool scope such as allowed-tools or permissions. In an agent environment, this increases the chance of over-privileged execution and unintended access to local or external resources, especially because the documentation includes auto-downloads, API calls, image generation, and subprocess use.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest omits material capabilities and destinations such as ChEMBL, PubMed/NCBI, and ADMET/query modules documented elsewhere in the skill. In agent ecosystems, incomplete disclosure can cause users and policy engines to approve a skill under false assumptions about what data leaves the environment and what analyses are performed.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The trigger description is extremely broad, making the skill likely to auto-activate for many ordinary chemistry-related conversations. Because this skill can perform network access, subprocess execution, file writes, and optional binary download, over-broad invocation increases the probability of unintended data transmission or execution in contexts where the user did not expect those operations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documentation states that the skill may automatically query external APIs and auto-download OPSIN on first use, but it does not provide a strong user-facing warning or consent flow. This is dangerous because user-supplied chemical names, structures, or research interests may be sent to third parties, and executable artifacts may be fetched and run without clear approval.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · chem_ui.py (reported line 30)May include surrounding context.

python
def analyze(smiles):
    smiles = _validate_smiles(smiles)
    # Props
    proc = subprocess.run(["python3", "rdkit_mol.py", "--smiles", smiles, "--action", "props"], cwd=WORK_DIR, capture_output=True, text=True)
    props = json.loads(proc.stdout)
    
    # Draw PNG

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest describes a chemistry query and RDKit/PubChem analysis skill, which would normally be implemented through in-process library/API calls. This file instead launches separate Python programs for molecule analysis and ADMET prediction, introducing process-execution capability that is broader than the stated chemistry-query role and not declared in the skill description.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The code runs external Python scripts via subprocess and writes an output image file (mol.png) as part of analysis, but there is no confirmation prompt, user-facing log/message, or explanatory warning in the code comments/docstrings beyond internal implementation notes. For a code file, these are safety-relevant operations that should be disclosed to the user unless clearly communicated elsewhere.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
77% confidence
Finding

Although this subprocess call is not directly shell-injectable, it causes a helper script to write to a fixed filename (mol.png) in a shared working directory. In a multi-user or concurrent environment, predictable shared output files can lead to race conditions, cross-request data leakage, file clobbering, or symlink abuse if an attacker can influence the filesystem.

Content

Scanner excerpt · chem_ui.py (reported line 34)May include surrounding context.

python
props = json.loads(proc.stdout)
    
    # Draw PNG
    subprocess.run(["python3", "rdkit_mol.py", "--smiles", smiles, "--action", "draw", "--output", "mol.png"], cwd=WORK_DIR)
    img = Image.open(os.path.join(WORK_DIR, "mol.png"))
    
    # ADMET

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · chem_ui.py (reported line 38)May include surrounding context.

python
img = Image.open(os.path.join(WORK_DIR, "mol.png"))
    
    # ADMET
    proc = subprocess.run(["python3", "admet_predict.py", "--smiles", smiles], cwd=WORK_DIR, capture_output=True, text=True)
    admet = json.loads(proc.stdout)
    
    return props, img, admet

Static analysis

No suspicious patterns detected.