Back to skill

Security audit

Command Guardian

Security checks for vulnerabilities and agentic risk

Overview

This is a local command safety checker, but it can echo sensitive commands back into reports and logs, so it needs review before use.

Install only if you are comfortable using it as an advisory local preflight checker, not a hard security boundary. Avoid passing live secrets via --command because the default JSON report can print the full command; prefer stdin or command files only when logs are controlled, and redact credentials before sharing transcripts. Treat path-escape results as helpful warnings but not definitive protection against symlink tricks.

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

Warning
Location
scripts/guardlib.py:808
Finding

Unredacted Commands Can Expose Inline Credentials in JSON Reports

Content
View full analysis

Vulnerability Details

File Location: scripts/guardlib.py:808, with output serialization at scripts/preflight.py:57
Vulnerability Type: Plaintext sensitive-data exposure
Risk Level: Medium

Vulnerable Code

scripts/guardlib.py:808:

python
return {
    "command": command,
    "cwd": os.path.abspath(cwd),
    "allowed_roots": [os.path.abspath(root) for root in (allowed_roots or [cwd])],
    "risk": risk,
    "need_approval": need_approval,
    "primary_command": classification["primary_command"],
    "subcommand": classification["subcommand"],
    "categories": categories,
    "reasons": reasons,
    "compound_parts": display_parts,
    "path_findings": paths["findings"],
    "secret_findings": secrets["findings"],
    "context_findings": context["details"],
    "rollback": rollback,
    "safer_actions": safer["actions"],
    "safer_commands": safer["commands"],
}

scripts/preflight.py:53-57:

python
if args.format == "text":
    print(format_text(report))
else:
    print(json.dumps(report, indent=2))

Technical Analysis

The secret-detection implementation masks recognized credentials in secret_findings, but preflight_report() also places the original, unmodified command in the report under the command field. JSON is the default output format, and preflight.py serializes the entire report to standard output.

Consequently, a command containing a bearer token, API key, cookie, password, JWT, or another credential can produce a report that contains both a masked finding and the original plaintext credential. Raw command segments may also remain in compound_parts, while generated safer commands can retain command content.

This conflicts with the Skill's purpose of detecting and reducing secret exposure. The implementation does not transmit reports over a network, but callers may capture standard output in Agent context, CI logs, shell trans ...[truncated 1147 chars]

Remediation
View remediation

Remediation Suggestions

  1. Redact recognized secrets before placing commands into any report field.
  2. Apply redaction consistently to:
    • command
    • compound_parts[*].command
    • nested command representations
    • safer_commands
    • reasons or diagnostics that might incorporate command fragments
  3. Preserve the original command only in process memory for analysis and never include it in serialized output after a secret is detected.
  4. Consider omitting the command field entirely when secret_findings is non-empty.
  5. Add a centralized redaction function that replaces every matched secret span rather than independently rebuilding report fields.
  6. Add regression tests asserting that sentinel credentials do not occur anywhere in serialized JSON or text output.
  7. Document that command-line arguments may themselves be visible in process listings or shell history, and recommend the existing --command-file or standard-input modes for sensitive commands.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/guardlib.py:147
Finding

Allowed-Root Validation Can Be Bypassed Through Symbolic Links

Content
View full analysis

Vulnerability Details

File Location: scripts/guardlib.py:147-168
Vulnerability Type: Incomplete filesystem boundary validation
Risk Level: Medium

Vulnerable Code

python
def resolve_path(raw_value, cwd):
    value = normalize_token(raw_value)
    if not value or is_remote_path(value):
        return ""
    expanded = os.path.expandvars(os.path.expanduser(value))
    if os.path.isabs(expanded) or is_windows_drive_path(expanded):
        return os.path.abspath(expanded)
    return os.path.abspath(os.path.join(cwd, expanded))


def path_within_roots(path, allowed_roots):
    if not path:
        return True
    target = os.path.abspath(path)
    for root in allowed_roots:
        base = os.path.abspath(root)
        try:
            if os.path.commonpath([target, base]) == base:
                return True
        except ValueError:
            continue
    return False

Technical Analysis

Path containment is determined using lexical normalization through os.path.abspath() and comparison through os.path.commonpath(). These operations normalize components such as . and .., but they do not resolve symbolic links.

A path can therefore appear lexically beneath an allowed workspace while resolving to a filesystem object outside it. For example, if /workspace/external is a symbolic link to /sensitive, then /workspace/external/file passes the lexical containment check even though filesystem operations target /sensitive/file.

The issue affects the accuracy of the preflight report rather than directly performing an unauthorized filesystem operation. The analyzer may omit a path-escape finding and provide misleading assurance about command scope.

Attack Path

  1. An allowed workspace contains, or an attacker creates, a symbolic link such as /workspace/external pointing to /outside.
  2. A command is submitted for analysis with a target such as `/works ...[truncated 1090 chars]
Remediation
View remediation

Remediation Suggestions

  1. Canonicalize allowed roots and existing target paths with os.path.realpath() or pathlib.Path.resolve().
  2. For a destination that does not yet exist:
    • locate its nearest existing parent;
    • resolve that parent canonically;
    • verify that the canonical parent is within an allowed root;
    • append only validated non-existing path components.
  3. Define an explicit symlink policy. For destructive operations, reject targets traversing symlinks unless they are intentionally permitted and their canonical destinations remain inside an allowed root.
  4. Consider race-resistant enforcement using directory file descriptors and platform facilities such as openat-style operations if this component later evolves from advisory analysis into command enforcement.
  5. Add tests covering:
    • symlinks inside the workspace pointing outside;
    • chained symlinks;
    • relative symlink destinations;
    • nonexistent files beneath symlinked directories;
    • symlinked allowed roots;
    • links changed between validation and execution.
  6. Continue treating the report as advisory and avoid presenting lexical containment as a hard security boundary unless execution is coupled to race-resistant path enforcement.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

This is another aspect of the same overclaiming issue: the skill claims broad preflight screening across multiple dangerous command classes, yet the visible artifact does not substantiate that capability. In safety tooling, overstated guarantees are dangerous because they can cause operators or agents to rely on protections that may not actually trigger.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This is another aspect of the same overclaiming issue: the skill claims broad preflight screening across multiple dangerous command classes, yet the visible artifact does not substantiate that capability. In safety tooling, overstated guarantees are dangerous because they can cause operators or agents to rely on protections that may not actually trigger.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · SKILL.md (reported line 53)May include surrounding context.

md
- Treat inline secrets as at least `high` risk. If the command embeds active credentials, treat it as `critical`.
- Treat destructive operations on broad targets such as `.`, `..`, `/`, drive roots, wildcard-only paths, or repo roots as `critical`.
- Treat `git push --force`, `git reset --hard`, `docker system prune`, `kubectl delete`, and `terraform apply/destroy` as requiring rollback guidance before execution.
- Treat `curl | sh` and similar download-and-execute patterns as `critical` unless the script is pinned, inspected, and verified.
- Treat compound commands by the highest-risk segment, not by the first visible token.
- If the current git branch is `main` or `master`, raise the review bar for destructive git commands.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · SKILL.md (reported line 99)May include surrounding context.

md
- Treat inline secrets as at least `high` risk. If the command embeds active credentials, treat it as `critical`.
- Treat destructive operations on broad targets such as `.`, `..`, `/`, drive roots, wildcard-only paths, or repo roots as `critical`.
- Treat `git push --force`, `git reset --hard`, `docker system prune`, `kubectl delete`, and `terraform apply/destroy` as requiring rollback guidance before execution.
- Treat `curl | sh` and similar download-and-execute patterns as `critical` unless the script is pinned, inspected, and verified.
- Treat compound commands by the highest-risk segment, not by the first visible token.
- If the current git branch is `main` or `master`, raise the review bar for destructive git commands.

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · SKILL.md (reported line 54)May include surrounding context.

md
- Treat inline secrets as at least `high` risk. If the command embeds active credentials, treat it as `critical`.
- Treat destructive operations on broad targets such as `.`, `..`, `/`, drive roots, wildcard-only paths, or repo roots as `critical`.
- Treat `git push --force`, `git reset --hard`, `docker system prune`, `kubectl delete`, and `terraform apply/destroy` as requiring rollback guidance before execution.
- Treat `curl | sh` and similar download-and-execute patterns as `critical` unless the script is pinned, inspected, and verified.
- Treat compound commands by the highest-risk segment, not by the first visible token.
- If the current git branch is `main` or `master`, raise the review bar for destructive git commands.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/tool-patterns.md (reported line 5)May include surrounding context.

md
## Git

- Prefer `git push --force-with-lease` over `git push --force`
- Before force-push or reset, create a backup branch from `HEAD`
- Use `git clean -ndx` before `git clean -fdx`
- Use `git reflog` as the primary rollback path after destructive history edits

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/tool-patterns.md (reported line 7)May include surrounding context.

md
- Prefer `git push --force-with-lease` over `git push --force`
- Before force-push or reset, create a backup branch from `HEAD`
- Use `git clean -ndx` before `git clean -fdx`
- Use `git reflog` as the primary rollback path after destructive history edits

## Docker

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · references/tool-patterns.md (reported line 28)May include surrounding context.

md
- Back up state before high-impact changes
- Treat `terraform destroy` and broad `-target` usage as high-risk operations

## curl and wget

- Treat `curl | sh`, `wget | bash`, or remote PowerShell execution as `critical`
- Prefer download, inspect, verify checksum or signature, then execute

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · references/tool-patterns.md (reported line 28)May include surrounding context.

md
- Back up state before high-impact changes
- Treat `terraform destroy` and broad `-target` usage as high-risk operations

## curl and wget

- Treat `curl | sh`, `wget | bash`, or remote PowerShell execution as `critical`
- Prefer download, inspect, verify checksum or signature, then execute

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · references/tool-patterns.md (reported line 30)May include surrounding context.

md
## curl and wget

- Treat `curl | sh`, `wget | bash`, or remote PowerShell execution as `critical`
- Prefer download, inspect, verify checksum or signature, then execute

## Package Managers

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · SKILL.md (reported line 53)May include surrounding context.

md
if subcommand == "reset" and "--hard" in command:
            categories.update({"write", "destructive"})
            risk = max_risk(risk, "critical")
            reasons.append("git reset --hard discards local changes")
        if subcommand == "clean" and re.search(r"(^|\s)-f", command):
            categories.update({"write", "destructive"})
            risk = max_risk(risk, "high")

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · scripts/guardlib.py (reported line 306)May include surrounding context.

python
if subcommand == "reset" and "--hard" in command:
            categories.update({"write", "destructive"})
            risk = max_risk(risk, "critical")
            reasons.append("git reset --hard discards local changes")
        if subcommand == "clean" and re.search(r"(^|\s)-f", command):
            categories.update({"write", "destructive"})
            risk = max_risk(risk, "high")

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · scripts/guardlib.py (reported line 619)May include surrounding context.

python
if subcommand == "reset" and "--hard" in command:
            categories.update({"write", "destructive"})
            risk = max_risk(risk, "critical")
            reasons.append("git reset --hard discards local changes")
        if subcommand == "clean" and re.search(r"(^|\s)-f", command):
            categories.update({"write", "destructive"})
            risk = max_risk(risk, "high")

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · scripts/guardlib.py (reported line 683)May include surrounding context.

python
if primary == "git" and subcommand == "push" and "--force" in command and "--force-with-lease" not in command:
        actions.extend([
            "Create a backup branch first",
            "Use git push --force-with-lease instead of plain --force",
        ])
        safer_commands.extend([
            f"git branch backup/pre-force-push{branch_suffix} HEAD",

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill explicitly instructs the agent to invoke local Python scripts and read reference files, which implies shell execution and file access, but it declares no tool scope or permission boundaries. In an agent environment, missing explicit tool restrictions can let the skill run with broader-than-intended capabilities and makes review and enforcement of least privilege harder.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill enables implicit invocation but the manifest does not define any clear activation constraints or limiting conditions. Because this skill reviews commands before execution, over-broad automatic triggering could cause command contents—including sensitive arguments, paths, or inline secrets—to be sent to the skill unexpectedly, expanding exposure and creating opportunities for prompt-injection or unintended mediation of unrelated tasks.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/guardlib.py (reported line 335)May include surrounding context.

python
risk = max_risk(risk, "critical")

    lowered = command.lower()
    if any(word in lowered for word in (" sudo ", " runas ", " -verb runas")) or lowered.startswith("sudo "):
        categories.add("privileged")
        risk = max_risk(risk, "high")
        reasons.append("command appears to require elevated privileges")

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/guardlib.py (reported line 559)May include surrounding context.

python
def git_context(cwd):
    try:
        root = subprocess.check_output(["git", "rev-parse", "--show-toplevel"], cwd=cwd, stderr=subprocess.DEVNULL, text=True).strip()
        branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=cwd, stderr=subprocess.DEVNULL, text=True).strip()
        status = subprocess.check_output(["git", "status", "--porcelain"], cwd=cwd, stderr=subprocess.DEVNULL, text=True)
        return {

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/guardlib.py (reported line 560)May include surrounding context.

python
def git_context(cwd):
    try:
        root = subprocess.check_output(["git", "rev-parse", "--show-toplevel"], cwd=cwd, stderr=subprocess.DEVNULL, text=True).strip()
        branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=cwd, stderr=subprocess.DEVNULL, text=True).strip()
        status = subprocess.check_output(["git", "status", "--porcelain"], cwd=cwd, stderr=subprocess.DEVNULL, text=True)
        return {
            "in_repo": True,

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/guardlib.py (reported line 561)May include surrounding context.

python
try:
        root = subprocess.check_output(["git", "rev-parse", "--show-toplevel"], cwd=cwd, stderr=subprocess.DEVNULL, text=True).strip()
        branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=cwd, stderr=subprocess.DEVNULL, text=True).strip()
        status = subprocess.check_output(["git", "status", "--porcelain"], cwd=cwd, stderr=subprocess.DEVNULL, text=True)
        return {
            "in_repo": True,
            "repo_root": root,

Static analysis

No suspicious patterns detected.