Back to skill

Security audit

swagger-skills

Security checks for vulnerabilities and agentic risk

Overview

This is a real Swagger/OpenAPI skill generator, but it needs review because it can expose documentation credentials and automatically install Python packages.

Review before installing or running with real credentials. Use only trusted Swagger/OpenAPI sources, prefer a disposable virtual environment, avoid putting real documentation passwords in sources.json, remove doc_auth from generated outputs before sharing or committing them, and verify generated API domains before allowing callers to send data.

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
scripts/build_swagger_skill.py:191
Finding
Documentation credentials can be disclosed to attacker-controlled discovery URLs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/build_swagger_skill.py:191-231, 263-286`; `scripts/swagger_client.py:127-157` **Vulnerability Type**: Cross-origin credential disclosure during Swagger specification discovery **Risk Level**: High ### Vulnerable Code ```python def candidate_urls(page_url: str, html: str) -> list[str]: """Extract possible spec URLs from a Swagger UI page.""" candidates: list[str] = [] patterns = [ r"\burl\s*:\s*['\"]([^'\"]+)['\"]", r"\burl\s*=\s*['\"]([^'\"]+)['\"]", r"['\"]url['\"]\s*:\s*['\"]([^'\"]+)['\"]", r"['\"]([^'\"]*(?:v2|v3)/api-docs[^'\"]*)['\"]", r"['\"]([^'\"]*swagger[^'\"]*\.(?:json|yaml|yml))['\"]", r"['\"]([^'\"]*openapi[^'\"]*\.(?:json|yaml|yml))['\"]", ] for pattern in patterns: for match in re.findall(pattern, html, flags=re.IGNORECASE): candidates.append(urljoin(page_url, match)) ``` ```python def expand_swagger_resources( resources: Any, page_url: str, ) -> list[str]: """Convert /swagger-resources payload into candidate spec URLs.""" if not isinstance(resources, list): return [] urls: list[str] = [] for item in resources: if isinstance(item, dict) and item.get("url"): urls.append(urljoin(page_url, str(item["url"]))) return urls ``` ```python auth = source.get("doc_auth") or defaults.get("doc_auth") or DEFAULT_DOC_AUTH timeout = int(source.get("timeout") or defaults.get("timeout") or 30) text, final_url = fetch_text(str(url), auth, timeout) parsed = parse_spec_text(text, final_url) if looks_like_spec(parsed): return parsed, final_url candidates = candidate_urls(final_url, text) for candidate in candidates: try: candidate_text, candidate_final_url = fetch_text(candidate, auth, timeout) except Exception: continue ``` ```python def make_session(auth_config: dict[str, Any] | None = None) -> requests.Session: """Create ...[truncated 2988 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Record the normalized origin of the explicitly configured source URL. 2. Before every authenticated request, compare the destination scheme, host, and effective port with the configured origin. 3. Attach documentation credentials only when the destination is same-origin. 4. Reject cross-origin candidates by default. If cross-origin specifications are required, use an explicit per-source allowlist and do not automatically reuse credentials. 5. Require HTTPS whenever a non-empty username or password is configured. 6. Reject HTTPS-to-HTTP redirects and validate the final response URL. 7. Separate unauthenticated discovery from authenticated retrieval: first validate the destination, then create a credential-bearing session only for an approved URL. 8. Add tests covering absolute URLs in Swagger HTML, cross-origin Swagger resources, redirects, alternate ports, and scheme changes. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/build_swagger_skill.py:1341
Finding
Documentation credentials are copied into generated Skills in plaintext<![CDATA[ ## Vulnerability Details **File Location**: `scripts/build_swagger_skill.py:1341-1357` **Vulnerability Type**: Unnecessary plaintext secret persistence **Risk Level**: Medium ### Vulnerable Code ```python source = config["source_by_id"].get(document_id, {}) auth = source.get("doc_auth") or config.get("defaults", {}).get("doc_auth") or DEFAULT_DOC_AUTH domains["documents"][document_id] = { "name": document_name, "description": document.get("description", ""), "spec_url": document.get("spec_url", ""), "base_url": base_url, "servers": servers, "env_key": document_env_key(document_id), "doc_auth": { "type": auth.get("type", "basic"), "username": auth.get("username", ""), "password": auth.get("password", ""), }, } ``` The resulting object is subsequently persisted through: ```python save_json(output_root / "config" / "domains.json", domains) ``` ### Technical Analysis Documentation credentials are needed only while downloading a protected Swagger/OpenAPI document. Nevertheless, the generator copies the username and password into each generated Skill's `config/domains.json`. The generated runtime request path in `scripts/skill_http.py` does not consume `doc_auth`; business API callers instead accept request headers from their caller. Retaining documentation credentials in runtime output therefore provides no demonstrated runtime benefit. The generated directory is explicitly intended to be reusable and distributable. Copying secrets into that directory unnecessarily expands the number of secret-bearing files and increases the chance of disclosure through source control, archives, artifact publication, backups, or file sharing. JSON provides no access control or encryption. ### Attack Path 1. A user replaces the placeholders in `config/sources.json` with real documentation credentials. 2. The user runs the generator. 3. `generate_files()` copies the credentials into the generated `config/domai ...[truncated 701 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `doc_auth` entirely from generated `config/domains.json`. 2. Keep documentation authentication build-only and in memory only for the duration of specification retrieval. 3. Accept credentials through environment variables, an operating-system credential store, or a dedicated secret manager instead of committed JSON. 4. If generated output needs to retain authentication metadata, retain only a non-sensitive reference such as an environment-variable name; never emit the secret value. 5. Add redaction checks that fail generation if password, token, or authorization fields would be written into output artifacts. 6. Document credential rotation procedures for users who previously generated or distributed affected artifacts. 7. Add generated directories and source files containing credentials to appropriate ignore rules, while treating ignore rules only as defense in depth. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/swagger_client.py:45
Finding
Module import can automatically install unpinned third-party dependencies<![CDATA[ ## Vulnerability Details **File Location**: `scripts/swagger_client.py:45-97`; `scripts/build_swagger_skill.py:23-31`; `requirements.txt:1-2` **Vulnerability Type**: Import-time package installation with insufficient dependency integrity controls **Risk Level**: Medium ### Vulnerable Code ```python def ensure_pip_available() -> None: """Ensure pip is available for the current interpreter.""" if importlib.util.find_spec("pip") is not None: return print("当前 Python 环境缺少 pip,正在尝试启用 ensurepip。") try: subprocess.check_call([sys.executable, "-m", "ensurepip", "--upgrade"]) except subprocess.CalledProcessError as exc: raise RuntimeError( "当前 Python 环境缺少 pip,且 ensurepip 启用失败。" "请先创建本地虚拟环境,或安装带 pip 的稳定版 Python。" ) from exc def ensure_requirements_installed(packages: dict[str, str] | None = None) -> None: """Install missing dependencies from the root requirements.txt.""" validate_python_runtime() package_map = packages or {"requests": "requests"} missing = [ requirement_name for import_name, requirement_name in package_map.items() if importlib.util.find_spec(import_name) is None ] if not missing: return ensure_pip_available() requirements_path = Path(__file__).resolve().parents[1] / "requirements.txt" if not requirements_path.exists(): package_list = " ".join(missing) command = [sys.executable, "-m", "pip", "install", *missing] print(f"检测到依赖缺失,正在安装:{package_list}") else: command = [sys.executable, "-m", "pip", "install", "-r", str(requirements_path)] print(f"检测到依赖缺失,正在根据 {requirements_path} 安装依赖。") try: subprocess.check_call(command, env={**os.environ, "PIP_DISABLE_PIP_VERSION_CHECK": "1"}) except subprocess.CalledProcessError as exc: raise RuntimeError( "依赖自动安装失败。常见原因是全局 Python 环境被 PEP 668 管理、pip 不可用、" "网络不可达,或 Python 版本 ...[truncated 2748 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all dependency installation calls from module-import paths. 2. If a dependency is missing, terminate with a clear error explaining how to install it in an isolated virtual environment. 3. Move installation into an explicit setup command that requires deliberate user action. 4. Pin dependencies to reviewed exact versions and maintain a lock file. 5. Use hash verification, such as pip's `--require-hashes`, for reproducible installation. 6. Install only from explicitly trusted package indexes and review any configured mirrors. 7. Avoid modifying global Python environments; recommend or enforce a project-specific virtual environment. 8. Run dependency vulnerability and provenance checks during release preparation. 9. Separate runtime dependencies from build-only dependencies so generated clients receive only the packages they need. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (34)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The declared purpose describes a documentation-to-skill generation capability: taking Swagger/OpenAPI links and producing organized API calling assets such as Python clients and field references. The supplied code does something materially narrower and different: it reads a local openapi_field_index.json-derived structure, matches entries for a given HTTP method and path, and rewrites JSON response keys into descriptive labels. There is no code for fetching or parsing Swagger/OpenAPI URLs, no skill generation, no client generation, and no domain configuration or navigation output. This is therefore a clear description-behavior mismatch, with the code implementing only a field-mapping utility rather than the declared end-to-end OpenAPI conversion workflow.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared purpose describes a generator/converter that consumes Swagger/OpenAPI documentation links and produces organized API-calling skills and related artifacts. The actual code chunk only implements lookup functionality over a prebuilt JSON field index. Its 'index' subcommand explicitly says rebuilding the index is not supported here, and the main functionality is searching entries by key or description with optional route/method filters. This is a materially different primary purpose from the declared description, so it should be flagged as a mismatch.

Self-Modification

High
Category
Rogue Agent
Content
def write_static_skill_files(skill_root: Path, skill_name: str, documents: list[dict[str, Any]]) -> None:
    """Write SKILL.md and README.md for one generated business skill."""

    skill_root.mkdir(parents=True, exist_ok=True)
    doc_names = [document["document_name"] for document in documents]
Confidence
85% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
This code explicitly serializes `username` and `password` values from documentation authentication into generated files. Embedding raw credentials in generated artifacts is dangerous because those files may be committed to source control, shared with users, or deployed to less trusted environments unrelated to spec discovery.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
print(f"检测到依赖缺失,正在根据 {requirements_path} 安装依赖。")

    try:
        subprocess.check_call(command, env={**os.environ, "PIP_DISABLE_PIP_VERSION_CHECK": "1"})
    except subprocess.CalledProcessError as exc:
        raise RuntimeError(
            "依赖自动安装失败。常见原因是全局 Python 环境被 PEP 668 管理、pip 不可用、"
Confidence
60% confidence
Finding
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The file title and all user-facing documentation are presented in Chinese, with no indication that other languages are supported or that this is an opt-in locale choice. Under the policy, forcing a specific language without user choice is a natural-language policy violation unless clearly documented as region-specific or optional.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
The entire skill documentation is written in Chinese, which imposes a specific language/locale on users without indicating any alternative language option. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill documentation describes capabilities that imply filesystem access, shell execution, network access, and configuration handling, but it does not declare any explicit tool scope or allowed-tools boundary. In an agent environment, this creates an over-privilege risk because the skill may be invoked with broader capabilities than necessary, increasing the blast radius of misuse or prompt-injection-driven actions.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The documentation instructs users to place documentation credentials directly into config files and does not warn about secret handling, storage hygiene, or exclusion from source control. This can lead to credential exposure through commits, shared workspaces, logs, or generated artifacts, especially because the skill also works with filesystem and generation workflows.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This markdown file explicitly documents that generated files read domain configuration and make HTTP requests via requests. Because network calls can affect privacy and transmit data externally, the skill description should clearly warn users about this behavior, but no such warning is present here.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This code generates SKILL.md and README.md with extensive Chinese-language instructions and user-facing content, including usage guidance and navigation text. The file does not indicate that the generated skills are intended only for Chinese-speaking users, nor does it provide an opt-in or alternative locale, which creates a natural-language locale policy concern.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
The generator copies `doc_auth` credentials used only for build-time Swagger/OpenAPI fetching into the generated `config/domains.json`, making those secrets persist in a broader runtime artifact. This expands credential exposure from the build environment into distributed generated skills, increasing the chance of accidental disclosure, reuse, or misuse by anyone who can read the generated files.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This code defines user-visible status and error text entirely in Chinese, and later emits those strings to users during normal operation. The file does not provide any opt-in, locale selection, or justification that the skill is intentionally limited to a Chinese-speaking context, which violates the language/locale policy criteria.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The command prints operational errors in Chinese only, and similar Chinese-only text appears in the command descriptions and hints. Because this is a general-purpose CLI script with no documented locale restriction or user choice, the natural-language behavior forces a specific language on all users.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The argparse description and subcommand help text are presented only in Chinese, which determines the user's interaction language regardless of preference. No opt-in, fallback, or documented region-specific constraint is present in this file.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This code performs outbound HTTP requests and may send query parameters, headers, JSON bodies, or raw data to external APIs. There is no confirmation prompt, user-facing log, or warning in the file indicating that user or system data may be transmitted over the network.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The file raises errors and prints guidance exclusively in Chinese, which enforces a specific language for user-visible interaction. Under the policy, locale or language restrictions should either be optional for the user or explicitly justified as region-specific; neither is present here.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
Automatically bootstrapping pip and installing dependencies is risky because it triggers code execution from external packages and changes the host environment as a side effect of using the module. That is disproportionate to the stated skill purpose and makes the skill more dangerous in agentic or automated environments where imports may happen implicitly.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
return
    print("当前 Python 环境缺少 pip,正在尝试启用 ensurepip。")
    try:
        subprocess.check_call([sys.executable, "-m", "ensurepip", "--upgrade"])
    except subprocess.CalledProcessError as exc:
        raise RuntimeError(
            "当前 Python 环境缺少 pip,且 ensurepip 启用失败。"
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
print(f"检测到依赖缺失,正在根据 {requirements_path} 安装依赖。")

    try:
        subprocess.check_call(command, env={**os.environ, "PIP_DISABLE_PIP_VERSION_CHECK": "1"})
    except subprocess.CalledProcessError as exc:
        raise RuntimeError(
            "依赖自动安装失败。常见原因是全局 Python 环境被 PEP 668 管理、pip 不可用、"
Confidence
84% confidence
Finding
The module automatically runs pip install via subprocess during normal import/use, which executes package installation code and performs network-dependent environment modification without explicit user consent. In a skill whose purpose is Swagger/OpenAPI transformation, this behavior is not necessary for core logic and increases supply-chain and execution risk, especially if requirements.txt is altered or the package index is untrusted.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The natural-language instructions in the skill are presented in Chinese throughout the document, and there is no indication that the user can choose another language or that the skill is intentionally restricted to a Chinese-speaking audience. This can violate a language/locale policy that requires user choice or justified locale constraints.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The natural-language documentation forces a specific language for users reading the skill description. Under the policy, language constraints should either offer user choice or be explicitly justified as locale-specific; neither is present in this file.

Natural-Language Policy Violations

Low
Confidence
96% confidence
Finding
The description value is written only in Chinese, which creates a language-specific constraint in a user-facing natural-language field. The file does not offer a language choice or explain that the skill is intentionally limited to a Chinese-language or region-specific context.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
The description string is written entirely in Chinese, which imposes a specific language in a user-facing natural-language field without any indication that this skill is region-specific or that users can choose another locale. This matches the policy concern for language or locale constraints that are not opt-in or justified.

Natural-Language Policy Violations

Low
Confidence
96% confidence
Finding
The README’s instructional content is written in Chinese and does not offer any language choice or note that the skill is intended only for a Chinese-speaking audience. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Static analysis

No suspicious patterns detected.