Back to skill

Security audit

Preflight

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent pre-publication review tool, with some privacy and prompt-injection hardening caveats but no evidence of malicious behavior.

Install only if you are comfortable sending draft content to the configured model endpoint. Use bundled personas or trusted project persona files, and avoid running it automatically on repositories you do not trust unless you review any preflight-personas.md first.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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)

T01 · Skill Instruction Hijacking

Warning
Location
scripts/preflight.py:124
Finding

Repository-Controlled Persona Content Is Promoted to a System Prompt

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:16-17, scripts/preflight.py:124-158, and scripts/preflight.py:176-181
Vulnerability Type: Prompt injection through untrusted project configuration
Risk Level: Medium

Vulnerable Code

SKILL.md:16-17:

markdown
Check for `preflight-personas.md` in the project root. If it exists, use those personas. Otherwise use the defaults in `references/personas.md`.

scripts/preflight.py:124-158:

python
def load_personas_from_file(path: str) -> list:
    """Parse personas from a markdown file."""
    personas = []
    current = None

    with open(path, 'r') as f:
        lines = f.readlines()

    for line in lines:
        line = line.rstrip()
        if line.startswith('### '):
            if current:
                personas.append(current)
            name = line[4:].strip()
            # Split on ( to get archetype
            if '(' in name:
                parts = name.split('(')
                name = parts[0].strip()
                archetype = parts[1].rstrip(')').strip()
            else:
                archetype = ""
            current = {"name": name, "archetype": archetype, "prompt": ""}
        elif current and line.startswith('- '):
            current["prompt"] += line[2:] + " "

    if current:
        personas.append(current)

    # Build proper prompts from bullet points
    for p in personas:
        if p["prompt"]:
            p["prompt"] = f"You are {p['name']} ({p['archetype']}). {p['prompt'].strip()}"

    return personas if personas else DEFAULT_PERSONAS

scripts/preflight.py:176-181:

python
response = client.chat.completions.create(
    model=model,
    messages=[
        {"role": "system", "content": persona["prompt"]},
        {"role": "user", "content": EVALUATION_PROMPT.format(content=content)}
    ],

Technical Analysis

The documented wor ...[truncated 2563 chars]

Remediation
View remediation

Remediation Suggestions

  1. Do not automatically trust persona definitions found in a project. Require explicit user approval before loading a project-level override, particularly for repositories from untrusted sources.
  2. Keep the system prompt entirely application-controlled. Pass custom persona fields as clearly delimited, quoted data in a lower-privilege message rather than using them as the complete system message.
  3. Define a strict persona schema containing only expected fields such as name, archetype, audience context, and preferences.
  4. Enforce length limits and reject unexpected sections, control characters, role markers, prompt delimiters, or instruction-like fields.
  5. Add an invariant system instruction stating that persona data is untrusted and cannot alter the evaluation task, output schema, safety constraints, or handling of supplied content.
  6. Request structured model output through a validated JSON schema rather than parsing unrestricted prose.
  7. Display the selected persona-file path and trust status before submission, and provide an option to force the bundled defaults.
  8. Treat all model responses as untrusted data and escape them appropriately if they are later rendered in terminals, web interfaces, or automation pipelines.

T08 · Insecure Dependencies

Note
Location
scripts/preflight.py:22
Finding

Unpinned Third-Party Dependency Installation Is Recommended

Content
View full analysis

Vulnerability Details

File Location: scripts/preflight.py:22-25
Vulnerability Type: Uncontrolled third-party dependency resolution
Risk Level: Low

Vulnerable Code

python
try:
    from openai import OpenAI
except ImportError:
    print("Error: openai package required. Install with: pip install openai")
    sys.exit(1)

Technical Analysis

When the openai package is unavailable, the script recommends installing it by package name without specifying a reviewed version, hash, lock file, or isolated environment. Executing pip install openai resolves whichever release the configured package index currently considers appropriate.

This makes the runtime environment dependent on mutable external package-index state. A future compromised, malicious, or incompatible release could be installed without a source change in this project. The recommendation also does not ensure that installation occurs inside a dedicated virtual environment, increasing the potential scope of dependency changes.

The package name itself is correctly spelled, and the reviewed project does not include evidence of dependency confusion, an attacker-controlled package source, or an intentionally malicious dependency. The finding is therefore a supply-chain hardening weakness rather than evidence that the current openai package is malicious.

Attack Path

  1. The script runs in an environment where the openai module is not installed.
  2. The import fails and the script displays pip install openai.
  3. The user executes the recommended command.
  4. pip resolves the dependency and its transitive dependencies from the user's configured package index without a project-enforced version or integrity hash.
  5. If the selected release or a transitive dependency has been compromised, malicious Python code can execute during installation or when openai is imported on the next run.

Impact Assessment

A malicious res ...[truncated 569 chars]

Remediation
View remediation

Remediation Suggestions

  1. Add a dependency manifest or lock file that pins a reviewed openai release and all relevant transitive dependencies.
  2. Use integrity hashes, such as a hash-locked requirements file generated with an appropriate dependency-management tool.
  3. Document installation in a dedicated virtual environment instead of recommending an unrestricted installation into the current interpreter.
  4. Configure trusted package indexes explicitly in deployment documentation and avoid unreviewed alternate indexes.
  5. Add automated dependency vulnerability and provenance scanning to the release process.
  6. Periodically update pinned dependencies through a controlled review and testing process rather than resolving the latest version during installation.
  7. Replace the bare command in the error message with a reference to the project's verified installation procedure.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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 (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill instructs the agent to read from the project root (preflight-personas.md) or a reference file, which implies file-read capability, but it does not declare any permissions or allowed-tools scope. That mismatch can cause the agent to access local files without explicit least-privilege controls or clear operator visibility into what filesystem access the skill requires.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger phrases are broad and overlap with normal copy-editing or feedback requests, so the skill may activate when the user did not intend a persona simulation workflow. Unintended invocation can lead to surprise file reads, unexpected behavior in larger autonomous pipelines, or the agent applying this skill in contexts where a simpler response was expected.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

This code sends user-provided content to an HTTP endpoint via the OpenAI-compatible client, with the default base URL set to a local Ollama server. Even though it is aimed at localhost, the content still leaves the process boundary and may be exposed to other local services, container port forwards, proxies, or a user-supplied alternate --base-url without any explicit warning or confirmation. In a pre-publication review tool, users may paste sensitive drafts, pricing changes, or embargoed announcements, so silent transmission creates a genuine confidentiality risk.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.