Back to skill

Security audit

JumpServer

Security checks for vulnerabilities and agentic risk

Overview

This JumpServer query skill has a legitimate purpose, but its credential-handling and runtime configuration choices create review-worthy risks before installation.

Review this skill carefully before installing. Use only least-privilege JumpServer credentials, avoid untrusted values in config-write payloads, do not set JMS_SDK_MODULE or JMS_SDK_GET_CLIENT unless you fully trust the module, protect .env.local, and prefer a version that verifies TLS certificates and pins dependencies.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/jms_runtime.py:286
Finding

Arbitrary Command Execution When Generated Environment Configuration Is Sourced

Content
View full analysis
str: return f"{key}={json.dumps(str(value), ensure_ascii=False)}" def write_local_env_config(payload: dict[str, Any]) -> dict[str, Any]: merged = _merge_config_values(payload) address_values = _resolve_address_values(merged) auth_mode, auth_values = _resolve_auth_values(payload, merged) final_values: dict[str, str] = {} final_values.update(address_values) final_values["JMS_VERSION"] = str(merged.get("JMS_VERSION") or "4") final_values["JMS_ORG_ID"] = str(merged.get("JMS_ORG_ID", "")) final_values.update(auth_values) timeout = merged.get("JMS_TIMEOUT") if _value_is_set(timeout): final_values["JMS_TIMEOUT"] = str(timeout) module_name = merged.get("JMS_SDK_MODULE") if _value_is_set(module_name): final_values["JMS_SDK_MODULE"] = str(module_name) attr_name = merged.get("JMS_SDK_GET_CLIENT") if _value_is_set(attr_name): final_values["JMS_SDK_GET_CLIENT"] = str(attr_name) lines = [ "# Generated by scripts/jms_diagnose.py config-write", "# Keep this file local. It may contain secrets.", "", ] for key in ( "JMS_API_URL", "JMS_VERSION", "JMS_ORG_ID", "JMS_ACCESS_KEY_ID", "JMS_ACCESS_KEY_SECRET", "JMS_USERNAME", "JMS_PASSWORD", "JMS_TIMEOUT", "JMS_SDK_MODULE", "JMS_SDK_GET_CLIENT", ): if key in final_values: lines.append(_format_env_assignment(key, final_values[key])) LOCAL_ENV_FILE.write_text("\n".join(lines) + "\n", encoding="utf-8") if os.name != "nt": LOCAL_ENV_FILE.chmod(0o600) ``` From `env.sh`: ...[truncated 2282 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/jms_runtime.py:466
Finding

TLS Certificate Verification Is Unconditionally Disabled

Content
View full analysis
Any: get_client = load_get_client() version = os.getenv("JMS_VERSION", "4") web_url = os.getenv("JMS_API_URL") kwargs: dict[str, Any] = { "version": version, "web_url": web_url, "verify": False, } access_key = os.getenv("JMS_ACCESS_KEY_ID") secret_key = os.getenv("JMS_ACCESS_KEY_SECRET") username = os.getenv("JMS_USERNAME") password = os.getenv("JMS_PASSWORD") if access_key and secret_key: kwargs["access_key"] = access_key kwargs["secret_key"] = secret_key elif username and password: kwargs["username"] = username kwargs["password"] = password timeout = os.getenv("JMS_TIMEOUT") if timeout: kwargs["timeout"] = int(timeout) client = get_client(**kwargs) org_id = os.getenv("JMS_ORG_ID") if org_id: client.set_org(org_id) return client ``` ### Technical Analysis Every SDK client is created with `verify=False`. The client therefore does not authenticate the JumpServer endpoint's TLS certificate. The associated `InsecureRequestWarning` is globally suppressed, preventing operators from seeing the warning that would normally expose the unsafe connection. The same client receives either the access key and secret key or the username and password. These credentials and all returned asset, permission, and audit data are transmitted over a channel that is encrypted but not authentic ...[truncated 1310 chars]
Remediation
View remediation

T07 · Tool Hijacking and Spoofing

Error
Location
scripts/jms_runtime.py:370
Finding

Configurable Dynamic Client Factory Enables Tool Hijacking and Credential Theft

Content
View full analysis
Any: module_name, attr_name = path.rsplit(".", 1) module = importlib.import_module(module_name) return getattr(module, attr_name) def load_get_client() -> Callable[..., Any]: load_local_env() module_name = os.getenv("JMS_SDK_MODULE", "jms_client.client") attr_name = os.getenv("JMS_SDK_GET_CLIENT", "get_client") return import_string(f"{module_name}.{attr_name}") ``` The dynamically selected function receives the credentials: ```python def _build_client() -> Any: get_client = load_get_client() version = os.getenv("JMS_VERSION", "4") web_url = os.getenv("JMS_API_URL") kwargs: dict[str, Any] = { "version": version, "web_url": web_url, "verify": False, } access_key = os.getenv("JMS_ACCESS_KEY_ID") s ...[truncated 2680 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Unpinned Dependency Can Be Automatically Installed During Operational Commands

Content
View full analysis
=0.9.1 ``` From `scripts/jms_bootstrap.py`: ```python def install_requirements(requirements_path: Path) -> None: command = [sys.executable, "-m", "pip", "install", "-r", str(requirements_path)] stderr_target = sys.stderr if sys.stderr is not None else subprocess.DEVNULL if sys.stderr is not None: print( f"[bootstrap] Installing missing Python dependencies from {requirements_path}", file=sys.stderr, ) completed = subprocess.run( command, stdout=stderr_target, stderr=stderr_target, check=False, ) if completed.returncode != 0: raise BootstrapError( "Automatic dependency installation failed. " f"Re-run with a working pip environment, or install manually with " f"{shlex.join(command)}." ) def ensure_requirements_installed(argv: list[str], confirm_install: bool) -> None: requirements_path = resolve_requirements_path() requirements = parse_requirements_file(requirements_path) installed = build_installed_distribution_map() unhealthy = find_unhealthy_requirements(requirements, installed) if not unhealthy: return unhealthy_names = ", ".join(requirement.name for requirement in unhealthy) if not confirm_install: raise BootstrapError( "Missing or unusable required Python packages from requirements.txt: " f"{unhealthy_names}. Re-run the same command with {CONFIRM_INSTALL_FLAG} to install " f"or repair them automatically: {build_retry_command(argv)}" ) install_requirements(requirements_path) installed_after_install = build_installed_distr ...[truncated 2601 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (33)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The documented purpose says the skill is limited to JumpServer preflight and read-only queries, but the detected behavior includes package installation/repair, dependency probing, and bootstrap logic outside that declared scope. This mismatch is dangerous because it can conceal higher-risk execution paths such as invoking pip or altering the runtime environment, which expands attack surface and violates operator expectations about a read-only skill.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · env.sh (reported line 3)May include surrounding context.

sh
#!/usr/bin/env bash

# Load JumpServer skill environment variables from a local .env.local file.
# Usage:
#   source ./env.sh
#

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · env.sh (reported line 7)May include surrounding context.

sh
#!/usr/bin/env bash

# Load JumpServer skill environment variables from a local .env.local file.
# Usage:
#   source ./env.sh
#

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · env.sh (reported line 25)May include surrounding context.

sh
#!/usr/bin/env bash

# Load JumpServer skill environment variables from a local .env.local file.
# Usage:
#   source ./env.sh
#

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/jms_diagnose.py (reported line 131)May include surrounding context.

python
#!/usr/bin/env bash

# Load JumpServer skill environment variables from a local .env.local file.
# Usage:
#   source ./env.sh
#

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · env.sh (reported line 17)May include surrounding context.

sh
SKILL_DIR="$(pwd)"
fi

LOCAL_ENV="$SKILL_DIR/.env.local"

set -a

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/jms_runtime.py (reported line 45)May include surrounding context.

python
SKILL_DIR="$(pwd)"
fi

LOCAL_ENV="$SKILL_DIR/.env.local"

set -a

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
98% confidence
Finding

The README explicitly documents that the runtime client uses verify=False and suppresses HTTPS certificate warnings, which disables TLS certificate validation. In a skill that collects credentials and connects to a remote JumpServer API, this materially increases the risk of man-in-the-middle interception, credential theft, and tampering with returned audit/asset data; the read-only scope does not meaningfully reduce exposure because authentication secrets and trusted query results are still at risk.

Content

Scanner excerpt · README.en.md (reported line 159)May include surrounding context.

md
Implementation notes:

- `scripts/jms_runtime.py` currently constructs the client with `verify=False`
- HTTPS certificate warnings are suppressed
- these two behaviors are not currently controlled by environment variables

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README explicitly instructs users to persist JumpServer credentials, including access keys or passwords, into a local .env.local file but does not warn about the sensitivity of those secrets or recommend filesystem protections, secret managers, or ephemeral alternatives. This increases the risk of credential disclosure through accidental commit, local compromise, backups, shell history, or overly broad file permissions.

Content

No source excerpt is available for this finding.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
98% confidence
Finding

The README documents that the runtime constructs the client with verify=False and suppresses HTTPS certificate warnings, which disables TLS certificate validation. In a skill that collects and uses JumpServer credentials and performs administrative queries, this makes man-in-the-middle interception materially more dangerous because an attacker could impersonate the server and capture secrets or tamper with returned data.

Content

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

md
实现备注:

- 当前 `scripts/jms_runtime.py` 在构造 client 时固定使用 `verify=False`
- HTTPS 证书告警会被抑制
- 这两个行为目前不是通过环境变量控制的

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill exposes capabilities that can write files, access environment data, and invoke shell commands, but it does not declare any explicit tool scope or permissions boundary in the skill metadata. That creates a least-privilege failure: consumers may treat the skill as a harmless read-only query helper while it can actually persist configuration and execute CLI actions, increasing the chance of unintended file modification or command execution.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The user-facing instructions, headings, and operational guidance are entirely written in Chinese, with no indication that other languages are supported or that the locale constraint is optional. This can violate a language/locale policy when a skill imposes a specific language without user opt-in or documented regional justification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The document explicitly describes and exemplifies writing sensitive credentials, including a plaintext password, into .env.local without any warning about secure handling, file permissions, shell history exposure, or secret rotation. In a security-adjacent operational skill, normalizing plaintext secret storage increases the chance of credential leakage through local files, backups, logs, screenshots, and command history.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This markdown file includes example values for JMS_ACCESS_KEY_SECRET and JMS_PASSWORD and documents config-write --confirm generating or updating .env.local, but it does not include any user warning about local secret storage, file protection, or avoiding accidental commit. For markdown files, user-affecting data and privacy behaviors should be disclosed clearly.

Content

No source excerpt is available for this finding.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
98% confidence
Finding

The runtime notes explicitly state that the client is constructed with verify=False and that HTTPS certificate warnings are suppressed. This disables TLS certificate validation, enabling man-in-the-middle interception or credential theft when connecting to JumpServer, which is especially dangerous because the skill handles sensitive authentication material and security-relevant administrative queries.

Content

Scanner excerpt · references/runtime-behavior.md (reported line 79)May include surrounding context.

md
## 实现备注

- 当前 `scripts/jms_runtime.py` 在构造 client 时固定使用 `verify=False`。
- HTTPS 证书告警会被抑制。
- 这两个行为目前不是通过环境变量控制的。

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This markdown file contains user-facing operational guidance only in Chinese, including headings, error explanations, and remediation steps. The file does not indicate that the skill is region-specific or provide an opt-in language choice, which can violate language/locale policy requirements.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The bootstrap logic can modify the local environment by automatically installing packages, which exceeds the declared read-only/query-oriented scope of the skill. Even with confirmation gating and restricted requirements parsing, this introduces supply-chain and environment-mutation risk: a user expecting read-only behavior may authorize execution that downloads and installs code from package indexes.

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 · scripts/jms_bootstrap.py (reported line 201)May include surrounding context.

python
f"[bootstrap] Installing missing Python dependencies from {requirements_path}",
            file=sys.stderr,
        )
    completed = subprocess.run(
        command,
        stdout=stderr_target,
        stderr=stderr_target,

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest describes this skill as supporting preflight, .env.local initialization, org selection, and read-only queries, but also explicitly frames it as not for business mutations. In this file, config_write writes local environment configuration via write_local_env_config, which is a state-changing operation rather than a read-only diagnostic/query action.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest allows org selection, but this file's behavior goes beyond transient selection by persisting JMS_ORG_ID to .env.local. That is a local state mutation and not a read-only query, so the implementation is broader than a strictly diagnostic/read-only tool.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This helper writes and mutates .env.local, including credentials and organization context, even though the skill is described as read-only and not for business mutations. That mismatch expands the trust boundary: an operator or wrapper invoking these helpers can change future runtime behavior and persisted auth state, creating persistence and configuration-tampering risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The function writes credentials into .env.local and chmods it, but there is no confirmation or warning at the write site itself that secrets are being persisted locally. In an agent skill context, silent local secret persistence increases the chance of unintended credential storage, later reuse, or exposure through backups, workspace sharing, or wrapper tooling.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code allows JMS_SDK_MODULE and JMS_SDK_GET_CLIENT from the environment to control what Python module and callable are imported and executed to construct the client. In a skill expected to perform bounded JumpServer read-only operations, this creates an unnecessary code-loading extension point that can be abused for arbitrary code execution if an attacker can influence the environment or .env.local contents.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The raised StructuredActionError messages are written in Chinese, and the file does not indicate that the skill is region-specific or provide an opt-in or fallback language. This creates a natural-language locale policy issue because the skill imposes a specific language on users without choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The file name README.en.md indicates an English-specific variant, but the document does not state that language is optional, user-selectable, or part of a justified locale-specific scope. Under the policy rule for natural-language constraints, forcing a specific language without opt-in can be a locale policy issue.

Content

No source excerpt is available for this finding.