Back to skill

Security audit

Bohrium Project Management

Security checks for vulnerabilities and agentic risk

Overview

The skill fits Bohrium project administration, but its unverified CLI installer and inconsistent API credential destination need careful review before installation.

Install only if you trust the Bohrium/DP Tech installer source and have verified the correct official API hostname. Prefer inspecting or checksum-verifying the installer before running it, use a least-privileged ACCESS_KEY if possible, and require explicit user approval before deleting projects, changing budgets, adding/removing members, or promoting/demoting admins.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:28
Finding

Unverified Remote Installation Scripts Are Downloaded and Executed Directly

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 28–33
Vulnerability Type: Remote payload retrieval and execution
Risk Level: Critical

bash
# macOS
/bin/bash -c "$(curl -fsSL https://dp-public.oss-cn-beijing.aliyuncs.com/bohrctl/1.0.0/install_bohr_mac_curl.sh)"

# Linux
/bin/bash -c "$(curl -fsSL https://dp-public.oss-cn-beijing.aliyuncs.com/bohrctl/1.0.0/install_bohr_linux_curl.sh)"

Technical Analysis

The installation instructions retrieve shell scripts from an external object-storage URL and pass the returned content directly to Bash. The downloaded content is not verified using a cryptographic signature, pinned digest, or published checksum before execution.

Although HTTPS and version-specific paths provide some protection, they do not guarantee that the server-side content remains immutable after the Skill has been reviewed. Anyone who compromises the hosting account, hosted object, DNS resolution, or relevant TLS trust infrastructure could alter the effective payload without modifying the audited Skill package.

This behavior exceeds the minimum privileges necessary for project management. Installing a prerequisite may be legitimate, but executing mutable network content without verification is not required to provide that functionality.

Attack Path

  1. An attacker compromises the object-storage account, distribution infrastructure, or another component capable of changing the installer response.
  2. The attacker replaces one of the installation scripts with a malicious shell payload.
  3. A user or agent follows the documented prerequisite instructions.
  4. curl retrieves the modified script.
  5. Command substitution passes the response directly to /bin/bash.
  6. The malicious script executes with all privileges and data access available to the invoking user.

Impact Assessment

Successful exploitation permits arbitrary command execution under the invoking user's account ...[truncated 316 chars]

Remediation
View remediation

Remediation Suggestions

  • Do not pipe or interpolate remote responses directly into a command interpreter.
  • Distribute the CLI through a trusted package manager or a signed, version-pinned release artifact.
  • Download the artifact to a local file before execution.
  • Publish and verify a SHA-256 digest obtained through an independently trusted channel.
  • Prefer cryptographic signature verification with a pinned vendor public key.
  • Fail closed if checksum or signature verification fails.
  • Present the downloaded script for inspection before execution when a package-based installation is unavailable.
  • Run installation with the lowest necessary privileges and avoid requesting administrative access unless strictly required.
  • Ensure release artifacts are immutable and protect the hosting account with strong access controls, audit logging, and multifactor authentication.

T09 · Insecure Skill Coding Practices

Error
Location
project_manager.py:20
Finding

Access Key Is Sent to an API Host That Conflicts with the Documented Destination

Content
View full analysis

Vulnerability Details

File Location: project_manager.py, lines 20–22; related documentation in SKILL.md, lines 160–166
Vulnerability Type: Sensitive credential transmission to an inconsistent endpoint
Risk Level: High

The implementation defines the following destination:

python
AK = os.environ.get("ACCESS_KEY", "")
BASE = "https://openapi.dp.tech/openapi/v1/project"
HEADERS = {"accessKey": AK}
HEADERS_JSON = {**HEADERS, "Content-Type": "application/json"}

The Skill documentation instead identifies a different API host:

python
import os, requests

AK = os.environ.get("ACCESS_KEY", "")
BASE = "https://open.bohrium.com/openapi/v1/project"
HEADERS = {"accessKey": AK}
HEADERS_JSON = {**HEADERS, "Content-Type": "application/json"}

Technical Analysis

project_manager.py reads the sensitive ACCESS_KEY environment variable and places it in the accessKey header of every API request. Credential transmission is necessary for authenticated Bohrium project management, but the executable sends the credential to openapi.dp.tech, whereas the documentation tells users that the API base is open.bohrium.com.

Both destinations use HTTPS and are hard-coded; the audited files do not prove that openapi.dp.tech is malicious or attacker-controlled. Nevertheless, the unexplained hostname mismatch prevents users from reliably validating the credential recipient and creates a material trust-boundary issue. A credential should only be transmitted to an explicitly documented and verified official endpoint.

The access key is reused for read and mutation operations, including listing member information, adding or removing members, changing budgets, renaming projects, and promoting or demoting administrators. Consequently, disclosure of the key may expose more than read-only project metadata.

Attack Path

  1. A user configures ACCESS_KEY based on the Skill's documentation and expectation ...[truncated 1217 chars]
Remediation
View remediation

Remediation Suggestions

  • Verify the official Bohrium OpenAPI hostname through authoritative vendor documentation.
  • Use the same verified hostname consistently in SKILL.md and project_manager.py.
  • Clearly disclose the exact domain that receives ACCESS_KEY.
  • Reject redirects for authenticated requests, or validate every redirect destination against a strict allowlist before forwarding credentials.
  • Use a dedicated, least-privileged token limited to the project-management operations required by the user.
  • Separate read-only credentials from credentials capable of membership, role, and budget mutations where the API supports that model.
  • Support token rotation and immediate revocation.
  • Add TLS certificate verification tests and retain the default secure certificate validation behavior.
  • Avoid logging the credential or complete authenticated request headers.
  • Add automated tests that fail when the executable API host differs from the documented host.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • 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 (27)

Tainted flow: 'HEADERS' from os.environ.get (line 23, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · project_manager.py (reported line 31)May include surrounding context.

python
def list_projects():
    """List all projects with details (cost, member count)."""
    r = requests.get(f"{BASE}/list", headers=HEADERS)
    items = r.json().get("data", {}).get("items", [])

    print(f"{'ID':<8} {'Name':<25} {'Role':<15} {'Members':<8} {'Total Cost':<12} {'Month Cost'}")

Tainted flow: 'HEADERS' from os.environ.get (line 23, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · project_manager.py (reported line 50)May include surrounding context.

python
def list_members(project_id: int):
    """List members of a project."""
    r = requests.get(f"{BASE}/{project_id}/users", headers=HEADERS)
    items = r.json().get("data", {}).get("items", [])

    if not items:

Tainted flow: 'HEADERS_JSON' from os.environ.get (line 24, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · project_manager.py (reported line 73)May include surrounding context.

python
def add_member(project_id: int, email: str):
    """Add a member to the project by email."""
    r = requests.post(
        f"{BASE}/add_user",
        headers=HEADERS_JSON,
        json={"projectId": project_id, "email": email},

Tainted flow: 'HEADERS_JSON' from os.environ.get (line 24, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · project_manager.py (reported line 87)May include surrounding context.

python
def remove_member(project_id: int, user_id: int):
    """Remove a member from the project."""
    r = requests.post(
        f"{BASE}/del_user",
        headers=HEADERS_JSON,
        json={"projectId": project_id, "userId": user_id},

Tainted flow: 'HEADERS_JSON' from os.environ.get (line 24, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · project_manager.py (reported line 101)May include surrounding context.

python
def set_budget(project_id: int, cost_limit: float):
    """Set project cost limit."""
    r = requests.post(
        f"{BASE}/set_cost_limit",
        headers=HEADERS_JSON,
        json={"projectId": project_id, "costLimit": cost_limit},

Tainted flow: 'HEADERS_JSON' from os.environ.get (line 24, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · project_manager.py (reported line 115)May include surrounding context.

python
def promote_admin(project_id: int, user_id: int):
    """Promote a member to admin."""
    r = requests.post(
        f"{BASE}/manager/add",
        headers=HEADERS_JSON,
        json={"projectId": project_id, "userId": user_id},

Tainted flow: 'HEADERS_JSON' from os.environ.get (line 24, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · project_manager.py (reported line 129)May include surrounding context.

python
def demote_admin(project_id: int, user_id: int):
    """Demote an admin to member."""
    r = requests.post(
        f"{BASE}/manager/del",
        headers=HEADERS_JSON,
        json={"projectId": project_id, "userId": user_id},

Tainted flow: 'HEADERS_JSON' from os.environ.get (line 24, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · project_manager.py (reported line 143)May include surrounding context.

python
def rename_project(project_id: int, name: str):
    """Rename a project."""
    r = requests.post(
        f"{BASE}/set_name",
        headers=HEADERS_JSON,
        json={"projectId": project_id, "name": name},

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill description understates and misstates the behavior exposed by the content: it includes renaming projects and changing member roles, while the declared purpose does not fully disclose those privileged actions. Capability-description drift is dangerous because users, orchestrators, and policy systems may approve the skill for lower-risk project management while it can also perform more sensitive administrative changes.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill includes operational shell commands and API examples that require environment access and network access, but it does not declare any explicit tool scope or allowed-tools boundary. This creates an authorization gap: an agent may invoke sensitive capabilities more broadly than reviewers or users expect, increasing the chance of unintended command execution or outbound requests with credentials.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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 · SKILL.md (reported line 131)May include surrounding context.

Set project cost limit via API:

python
requests.post(f"{BASE}/set_cost_limit", headers=HEADERS_JSON,
    json={"projectId": 154, "costLimit": 5000})

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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 · SKILL.md (reported line 207)May include surrounding context.

Set project cost limit via API:

python
requests.post(f"{BASE}/set_cost_limit", headers=HEADERS_JSON,
    json={"projectId": 154, "costLimit": 5000})

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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 · SKILL.md (reported line 203)May include surrounding context.

md
r = requests.get(f"{BASE}/lite_list", headers=HEADERS)

# Rename project
requests.post(f"{BASE}/set_name", headers=HEADERS_JSON,
    json={"projectId": 154, "name": "new-name"})

# Set cost limit

External Transmission

Medium
Category
Data Exfiltration
Confidence
78% confidence
Finding

Adding a member by email sends personal data to the external service and triggers an access-control change on the project. In the context of an agent skill, this is more sensitive than ordinary network use because it combines PII handling with security-relevant authorization changes, yet the skill lacks explicit warnings, consent language, or scoped safeguards.

Content

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

md
# Returns: {items: [{userId, userName, email, projectRole, cost, ...}]}

# Add member (by email)
requests.post(f"{BASE}/add_user", headers=HEADERS_JSON,
    json={"projectId": 154, "email": "user@example.com"})

# Remove member

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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 · SKILL.md (reported line 219)May include surrounding context.

md
json={"projectId": 154, "email": "user@example.com"})

# Remove member
requests.post(f"{BASE}/del_user", headers=HEADERS_JSON,
    json={"projectId": 154, "userId": 12345})

# Promote/demote admin

External Transmission

Medium
Category
Data Exfiltration
Confidence
77% confidence
Finding

Promoting a user to admin is a privilege-escalation action sent to an external API. In this skill context, that is especially dangerous because administrative role changes affect access to project resources and billing controls, yet the capability is not fully disclosed in the skill description and is not guarded by explicit permission scope.

Content

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

md
json={"projectId": 154, "userId": 12345})

# Promote/demote admin
requests.post(f"{BASE}/manager/add", headers=HEADERS_JSON,
    json={"projectId": 154, "userId": 12345})
requests.post(f"{BASE}/manager/del", headers=HEADERS_JSON,
    json={"projectId": 154, "userId": 12345})

External Transmission

Medium
Category
Data Exfiltration
Confidence
77% confidence
Finding

Demoting an admin is an external authorization-changing action that can disrupt governance and access to project resources. In an agent environment, undocumented privilege-management endpoints increase the risk of misuse or surprising destructive changes by users who only expected routine project administration.

Content

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

md
# Promote/demote admin
requests.post(f"{BASE}/manager/add", headers=HEADERS_JSON,
    json={"projectId": 154, "userId": 12345})
requests.post(f"{BASE}/manager/del", headers=HEADERS_JSON,
    json={"projectId": 154, "userId": 12345})

# Recover deleted member

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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 · SKILL.md (reported line 229)May include surrounding context.

json={"projectId": 154, "userId": 12345})

Recover deleted member

requests.put(f"{BASE}/154/recovery_user", headers=HEADERS_JSON, json={"userId": 12345})

text

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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 · project_manager.py (reported line 73)May include surrounding context.

python
def add_member(project_id: int, email: str):
    """Add a member to the project by email."""
    r = requests.post(
        f"{BASE}/add_user",
        headers=HEADERS_JSON,
        json={"projectId": project_id, "email": email},

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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 · project_manager.py (reported line 87)May include surrounding context.

python
def remove_member(project_id: int, user_id: int):
    """Remove a member from the project."""
    r = requests.post(
        f"{BASE}/del_user",
        headers=HEADERS_JSON,
        json={"projectId": project_id, "userId": user_id},

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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 · project_manager.py (reported line 101)May include surrounding context.

python
def set_budget(project_id: int, cost_limit: float):
    """Set project cost limit."""
    r = requests.post(
        f"{BASE}/set_cost_limit",
        headers=HEADERS_JSON,
        json={"projectId": project_id, "costLimit": cost_limit},

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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 · project_manager.py (reported line 115)May include surrounding context.

python
def promote_admin(project_id: int, user_id: int):
    """Promote a member to admin."""
    r = requests.post(
        f"{BASE}/manager/add",
        headers=HEADERS_JSON,
        json={"projectId": project_id, "userId": user_id},

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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 · project_manager.py (reported line 129)May include surrounding context.

python
def demote_admin(project_id: int, user_id: int):
    """Demote an admin to member."""
    r = requests.post(
        f"{BASE}/manager/del",
        headers=HEADERS_JSON,
        json={"projectId": project_id, "userId": user_id},

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The file implements project renaming even though the declared skill scope says it should be used for creating/listing/deleting projects, member management, and cost limits only. Capability drift is dangerous because agents or reviewers may authorize the skill based on the manifest while the code can perform additional state-changing actions that were not disclosed.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

This external transmission performs a project rename action that is not declared in the skill metadata or module usage text. In an agent setting, undisclosed state-changing network operations are risky because they expand what the skill can do beyond reviewer and user expectations, enabling unintended modification of remote resources.

Content

Scanner excerpt · project_manager.py (reported line 143)May include surrounding context.

python
def rename_project(project_id: int, name: str):
    """Rename a project."""
    r = requests.post(
        f"{BASE}/set_name",
        headers=HEADERS_JSON,
        json={"projectId": project_id, "name": name},

Static analysis

No suspicious patterns detected.