Back to skill

Security audit

Agent OKR

Security checks for vulnerabilities and agentic risk

Overview

This OKR-management skill is mostly coherent, but its bundled validator has a real code-execution flaw triggered by crafted OKR filenames.

Review before installing. The OKR workflow itself is understandable, but do not run scripts/validate-okr.sh on directories that may contain untrusted filenames until the validator passes file paths as arguments instead of interpolating them into Python source. Require explicit user approval for weekly report writes and keep changes limited to the intended docs/agent-okr path.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/validate-okr.sh:21
Finding

Arbitrary Python Code Execution Through Crafted OKR Filename

Content
View full analysis

Vulnerability Details

File Location: scripts/validate-okr.sh, lines 21–29
Vulnerability Type: Python source injection through unsafe filename interpolation
Risk Level: High

Vulnerable Code

bash
for f in "$OKR_DIR"/*.yaml "$OKR_DIR"/*.yml; do
  [ -f "$f" ] || continue
  fname=$(basename "$f")
  
  ISSUES=$(python3 -c "
import yaml, sys

with open('$f') as fh:
    try:

Technical Analysis

The path stored in $f is expanded directly into source code supplied to python3 -c. Although the shell variable is inside a double-quoted shell string, its value is placed inside a single-quoted Python string literal:

python
with open('$f') as fh:

Shell quoting does not protect the generated Python program from Python-language injection. A filename may legally contain single quotes, parentheses, operators, and other characters that alter the resulting Python expression.

For example, a filename can terminate the original string and append an expression that invokes __import__() and executes a system command while Python evaluates the argument passed to open(). Command execution occurs before open() attempts to access the resulting path, so the eventual failure to open that path does not prevent payload execution.

The YAML file contents do not need to contain malicious Python; the filename itself is the injection channel.

Attack Path

  1. An attacker obtains the ability to add or commit a file under the expected docs/agent-okr directory.
  2. The attacker gives a .yaml or .yml file a crafted name containing a single quote and a Python expression.
  3. A user, automated agent, or CI process invokes scripts/validate-okr.sh.
  4. The shell expands the glob and stores the attacker-controlled path in $f.
  5. $f is interpolated into the program passed to python3 -c.
  6. Python parses the crafted filename as part of its source code and evaluates the injected expression.
  7. The injected command executes with the privileges ...[truncated 684 chars]
Remediation
View remediation

Remediation Suggestions

Never interpolate a filesystem path into executable Python source. Pass the path as a positional argument and use a quoted heredoc so that shell expansion cannot modify the Python program:

bash
ISSUES=$(python3 - "$f" <<'PY'
import sys
import yaml

path = sys.argv[1]

with open(path, encoding="utf-8") as fh:
    try:
        d = yaml.safe_load(fh)
    except yaml.YAMLError as exc:
        print(f"ERRORS:YAML parsing failed: {exc}")
        sys.exit(0)

# Continue validation here.
PY
)

Additional hardening measures should include:

  • Keep the heredoc delimiter single-quoted to disable shell interpolation.
  • Treat all discovered paths as untrusted input, even when they originate in the repository.
  • Run the validator with minimum necessary filesystem and CI permissions.
  • Add a regression test using filenames containing quotes, spaces, newlines, and Python metacharacters.
  • Consider implementing the complete directory scan in Python using pathlib, eliminating cross-language string construction.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/validate-okr.sh:26
Finding

Malformed YAML Root Can Abort Validation of All Remaining Files

Content
View full analysis

Vulnerability Details

File Location: scripts/validate-okr.sh, lines 26–39
Vulnerability Type: Unhandled input type and validation denial of service
Risk Level: Low

Vulnerable Code

python
with open('$f') as fh:
    try:
        d = yaml.safe_load(fh)
    except yaml.YAMLError as e:
        print(f'ERRORS:YAML解析失败: {e}')
        sys.exit(0)

errors = []

# Required fields
for field in ['agent', 'period', 'status', 'objective', 'mainline', 'key_results']:
    if field not in d:
        errors.append(f'缺少必填字段: {field}')

# Validate key_results
krs = d.get('key_results', [])

The shell also enables immediate termination:

bash
set -euo pipefail

Technical Analysis

yaml.safe_load() does not guarantee that the document root is a mapping. Depending on the input, it can return:

  • None for an empty document;
  • a string, number, or Boolean for a scalar document;
  • a list for a sequence document;
  • a dictionary for the expected mapping document.

The validator immediately uses membership checks and .get() as though d were always a dictionary. An empty document can cause a TypeError during field not in d, while a list or scalar can cause incorrect behavior or an AttributeError at d.get(...).

These exceptions are not caught. The command substitution therefore returns a nonzero status, and the script's set -e behavior can terminate the validator before it processes the remaining OKR files or prints a complete result.

Attack Path

  1. An attacker or ordinary contributor creates an empty OKR YAML file, or a YAML document whose root is a scalar or sequence.
  2. The file is placed in docs/agent-okr with a .yaml or .yml extension.
  3. The validator parses the file successfully because the YAML syntax itself is valid.
  4. The returned object is not a dictionary.
  5. A membership operation or .get() call raises an unhandled Python exception.
  6. The Python process exits unsuccessfully.
  7. Because the shell uses `se ...[truncated 482 chars]
Remediation
View remediation

Remediation Suggestions

Validate the deserialized root type immediately after parsing and report unsupported document types as ordinary validation failures:

python
with open(path, encoding="utf-8") as fh:
    try:
        d = yaml.safe_load(fh)
    except yaml.YAMLError as exc:
        print(f"ERRORS:YAML parsing failed: {exc}")
        sys.exit(0)

if not isinstance(d, dict):
    print("ERRORS:YAML root must be a mapping")
    sys.exit(0)

Further hardening should include:

  • Catch OSError for inaccessible or disappearing files.
  • Keep validation errors distinct from internal validator failures.
  • Ensure one invalid file does not stop processing of other files.
  • Add tests for empty documents, scalar roots, sequence roots, aliases, and syntactically invalid YAML.
  • Return a final nonzero status after all files have been inspected rather than terminating during the first malformed input.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

SQP-3 applies to all file types and includes language or locale policy violations. The skill content consistently forces Chinese-language interaction and documentation, with no indication that users may choose another language or that the Chinese-only constraint is required for a specific region or compliance reason.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill explicitly describes an automatic workflow that generates weekly reports and writes them into docs/agent-okr/{agent-name}.yaml, but it does not state any confirmation, authorization, or safe-guarding requirements before modifying repository data. In an agent setting, silent file writes can lead to unintended state changes, unauthorized updates, or workflow abuse if the skill is invoked in the wrong context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script's natural-language comments and all user-facing status/error messages are in Chinese, which imposes a specific language on users. The policy allows locale constraints only when they are justified or optional, but this file provides no opt-in, alternative language, or documented regional limitation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.