Back to skill

Security audit

output-schema-guard

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent JSON schema-guard helper, but its advertised validation gate can fail open and its install instructions use mutable, unpinned sources.

Review before installing. The skill does not appear malicious or designed to steal data, but do not rely on its CLI exit status as a security or CI gate until the fail-open behavior is fixed. Prefer a pinned, reviewable install source instead of the documented global npx command.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/schema_guard.py:66
Finding
Validation Failures Return a Successful Process Exit Code<![CDATA[ ## Vulnerability Details **File Location**: `scripts/schema_guard.py`, lines 66-82 **Vulnerability Type**: Fail-open validation gate **Risk Level**: High ### Vulnerable Code ```python obj, err = load_json_text(src) if err: issues = [{"field": "(root)", "expected": "合法 JSON", "got": "解析失败", "hint": err}] print(json.dumps({"pass": False, "issues": issues}, ensure_ascii=False, indent=2) if a.json else f"❌ {err}") return issues = validate(obj, schema) if a.json: print(json.dumps({"pass": not issues, "issues": issues}, ensure_ascii=False, indent=2)) else: print(f"校验:{'✅ 通过' if not issues else '🔒 拦截'} 问题:{len(issues)}") for i in issues: print(f" [{i['field']}] 期望 {i['expected']} | 实际 {i['got']} | 修复:{i['hint']}") if __name__ == "__main__": main() ``` ### Technical Analysis The CLI documents exit code `1` for validation failures and exit code `2` for usage or environment errors, but `main()` does not return or raise a nonzero process status when malformed JSON or schema violations are detected. The parsing-failure branch uses a bare `return`, while ordinary validation failures only affect printed output. Python consequently terminates with exit code `0` in both cases. This creates a fail-open validation boundary whenever a shell script, CI job, agent, or downstream program relies on the process status instead of parsing the human-readable output. ### Attack Path 1. A downstream workflow invokes the validator as a security or data-quality gate. 2. The workflow determines success using the command's exit status. 3. An attacker supplies malformed JSON, omits required fields, or provides values that violate the schema. 4. The validator prints a rejection message but exits with status `0`. 5. The calling workflow interprets the command as successful and permits the untrusted output to continue into business logic, storage, or an API. ### Impact Assessment No additio ...[truncated 360 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make `main()` return explicit status codes: - `0` when validation succeeds. - `1` when input parsing or validation rejects the submitted data. - `2` when the schema, command-line usage, or execution environment is invalid. 2. Terminate with the returned status: ```python if __name__ == "__main__": raise SystemExit(main()) ``` 3. Ensure both human-readable and JSON output modes use identical exit semantics. 4. Add automated tests that execute the CLI as a subprocess and assert the exit code for valid JSON, malformed JSON, missing required fields, invalid types, invalid enums, unreadable files, and malformed schemas. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/schema_guard.py:15
Finding
Unsupported Schema Types Are Silently Accepted<![CDATA[ ## Vulnerability Details **File Location**: `scripts/schema_guard.py`, lines 15-28 **Vulnerability Type**: Fail-open schema interpretation **Risk Level**: Medium ### Vulnerable Code ```python def check_type(val, t): if t == "str": return isinstance(val, str) if t == "int": return isinstance(val, int) and not isinstance(val, bool) if t == "float": return isinstance(val, (int, float)) and not isinstance(val, bool) if t == "bool": return isinstance(val, bool) if t == "list": return isinstance(val, list) if t == "dict": return isinstance(val, dict) return True ``` ### Technical Analysis The final `return True` treats every unknown type identifier as successfully validated. A misspelled type, unsupported alias, or malformed schema therefore disables the intended type check without warning. A secure schema validator should reject unsupported schema constructs before validating input. Treating an unknown rule as successful converts a configuration error into a silent fail-open condition. ### Attack Path 1. A schema contains an unsupported or misspelled type, such as `"integer"` instead of `"int"`. 2. An attacker supplies a value whose actual type should be rejected. 3. `check_type()` reaches the default branch and returns `True`. 4. No type issue is added to the validation result. 5. The attacker-controlled value passes the intended type boundary and reaches downstream processing. ### Impact Assessment This issue does not directly grant system privileges. It compromises the integrity of data accepted under malformed schemas. The practical scope includes downstream APIs, database writes, form processing, and agent tool calls that rely on the validator to enforce argument types. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define an explicit allowlist of supported schema types. 2. Validate the schema before processing untrusted input. 3. Reject unknown type identifiers as schema errors rather than treating them as successful checks. 4. Return exit code `2` for an invalid schema. 5. Include the field name and unsupported type in structured error output. 6. Add tests for misspelled, empty, non-string, and otherwise unsupported type declarations. For example: ```python SUPPORTED_TYPES = {"str", "int", "float", "bool", "list", "dict"} if t not in SUPPORTED_TYPES: raise ValueError(f"Unsupported schema type: {t}") ``` ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:96
Finding
Documented Installation Command Executes Unpinned Third-Party Code<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, line 96 **Vulnerability Type**: Unpinned executable dependency and mutable installation source **Risk Level**: Medium ### Vulnerable Code ```bash npx skills add zhaoxinghua09-cell/agent-skills -g ``` ### Technical Analysis The installation instructions invoke `npx` without pinning the `skills` package to a specific version or integrity digest. Depending on the local environment, `npx` may download and execute the current registry version of that package. The command also installs content from a repository reference that is not pinned to a reviewed commit. The effective code executed during installation can therefore change after this artifact has been audited. This creates a supply-chain trust gap between the reviewed package and the documented installation procedure. ### Attack Path 1. An attacker compromises the registry package used by `npx`, its maintainer account, or the referenced repository. 2. The attacker publishes a modified package or changes repository content. 3. A user follows the documented one-line installation command. 4. `npx` retrieves and executes the mutable package version. 5. The compromised installer or repository content executes with the invoking user's permissions and may install additional modified skill files globally. ### Impact Assessment The executable code receives the privileges of the user running the installation command. Its scope may include access to that user's files, environment variables, network credentials, agent configuration, and global skill directories writable by the user. If a user independently runs the command with elevated privileges, the potential scope increases accordingly; the documentation itself does not require elevation. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the `skills` CLI to a reviewed, exact version. 2. Pin the source repository to a specific immutable commit rather than a mutable branch. 3. Publish and verify checksums or cryptographic signatures for downloaded artifacts. 4. Avoid global installation by default and document the precise files and permissions modified. 5. Prefer a download-and-verify workflow that allows users to inspect the artifact before execution. 6. Document the trusted registry, package identity, expected digest, and repository commit. 7. Periodically audit the pinned dependency and deliberately update the pin after review. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/schema_guard.py:35
Finding
Non-Object JSON Roots Can Crash the Validator<![CDATA[ ## Vulnerability Details **File Location**: `scripts/schema_guard.py`, lines 35-44 **Vulnerability Type**: Improper input-type validation and denial of service **Risk Level**: Low ### Vulnerable Code ```python for f in required: if f not in fields: fields[f] = {"required": True} for name, spec in fields.items(): must = spec.get("required", name in required) present = obj is not None and name in obj and obj[name] is not None if must and not present: issues.append({"field": name, "expected": "存在(必填)", "got": "缺失", "hint": f"补充必填字段 {name}"}) continue if not present: continue ``` ### Technical Analysis The validator assumes that the parsed JSON root supports mapping membership and string-key indexing, but it never confirms that `obj` is a dictionary. Valid JSON can have a scalar, string, array, boolean, or null root. For numeric or boolean roots, `name in obj` raises a `TypeError`. For string roots, membership may succeed when a field name is a substring, after which `obj[name]` raises another `TypeError`. These exceptions are not caught, so the process can emit a traceback and terminate unexpectedly. ### Attack Path 1. An attacker supplies syntactically valid JSON whose root is not an object, such as `1`, `true`, or a crafted string. 2. `json.loads()` accepts the input. 3. `validate()` evaluates membership or indexing operations under the assumption that the root is a mapping. 4. Python raises an unhandled `TypeError`. 5. The validator crashes, disrupting the calling workflow and potentially exposing internal paths through the traceback. ### Impact Assessment No privilege escalation occurs. The primary impact is availability: an attacker who controls validator input can reliably terminate the process. The exception output may also disclose local filesystem paths and call-stack details. The scope is limited to workflows that process attacker-controlle ...[truncated 45 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Verify the root type before iterating over schema fields: ```python if not isinstance(obj, dict): return [{ "field": "(root)", "expected": "object", "got": type(obj).__name__, "hint": "Provide a JSON object at the document root", }] ``` 2. Emit a structured validation failure instead of allowing a runtime exception. 3. Use a nonzero validation exit code for an invalid root. 4. Catch expected parsing, file-access, and schema-processing exceptions at the CLI boundary without exposing raw tracebacks. 5. Add tests for string, number, boolean, array, and null JSON roots. ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (7)

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The file title and body present the skill in both English and Chinese, but key branding and descriptive text explicitly include Chinese-language content as part of the default presentation. Under the stated policy, forcing a specific language or locale without user opt-in can be a natural-language policy violation when no language choice is offered.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The manifest description, summary, and later operating instructions are presented in Chinese as the default, which can force a specific language experience on users. The policy allows locale constraints only when users are given a choice or when the constraint is clearly justified, neither of which is stated here.

Rp1

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding
The installation instruction uses 'npx skills add ...' without pinning a specific package version. That allows future upstream package changes or a compromised dependency to alter what gets executed at install time, creating a supply-chain risk for users who follow the command.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
SQP-3 applies to all file types and covers language/locale policy violations in natural-language content. The module docstring at L02 specifies behavior only in Chinese, which can force a language choice on users without offering an option.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
The heading presents the skill attestation in Chinese first and English second, indicating a specific language/localization choice in user-facing natural language. The file does not state that language selection is optional or justified by a region-specific requirement, which can conflict with language/locale policy expectations.

Natural-Language Policy Violations

Low
Confidence
76% confidence
Finding
The manifest uses the category value "AI工程方法", which is a Chinese-language label, but the file provides no indication that the skill is region-specific or that users can choose a preferred language/locale. Under the policy, forcing or implicitly assuming a specific language without opt-in can be a natural-language policy concern.

Static analysis

No suspicious patterns detected.