Back to skill

Security audit

Code Analysis Skills

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed local Git-history reflection tool, but its handling of personal developer data has consent-scoping and report-rendering risks that need review.

Install only for your own repositories or a team retrospective where every included contributor has clearly opted in. Avoid broad scan-all runs on shared workspaces unless the path is tightly chosen. Prefer Markdown or JSON output until HTML escaping and PDF resource restrictions are fixed, and treat generated reports as sensitive personal data.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
src/analyzers/base_analyzer.py:82
Finding

Substring-Based Author Matching Can Analyze Non-Consenting Identities

Content
View full analysis
bool: """Check whether a commit's author name/email is in the consent-resolved identity set populated by the orchestrator.""" for author_filter in self.authors: af_lower = author_filter.lower() if af_lower in name.lower() or af_lower in email.lower(): return True return False ``` ### Technical Analysis The consent enforcement mechanism uses unrestricted, case-insensitive substring matching instead of matching complete canonical identities. A consent filter such as `Ann` will match not only an author named `Ann`, but also identities such as: - `Joanne` - `Annette` - `ann-attacker@example.com` - `not-ann@example.org` The same issue affects self-scope mode because the local Git user's name and email are passed into this matching function. Although a complete email generally reduces ambiguity, the local name is also included as an independent filter, and a matching result from either filter is sufficient. This behavior conflicts with the stated guarantee that only the current user or explicitly listed consenting authors are analyzed. Git author metadata is not authenticated and can be freely selected when creating a commit, so it must not be treated as a reliable authorization identifier through fuzzy matching. ### Attack Path 1. A legitimate developer named `Ann` consents to analysis, or the local Git configuration id ...[truncated 1261 chars]
Remediation
View remediation
bool: normalized_name = (name or "").strip().casefold() normalized_email = (email or "").strip().casefold() for identity in self.authorized_identities: if normalized_email and normalized_email == identity.email: return True if ( identity.email is None and normalized_name and normalized_name == identity.name ): return True return False ``` 6. In self-scope mode, require an exact email match when a local Git email is configured. Do not also accept arbitrary names containing the local user's name. 7. Add tests for colliding identities such as `Ann`, `Joanne`, `Annette`, and `ann-attacker@example.com`. 8. Record the exact resolved identities in scope metadata so the report accurately describes whose commits were processed. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
src/reporters/html_reporter.py:159
Finding

Unescaped Git and Filesystem Metadata Enables Stored HTML Injection

Content
View full analysis
📁 {{ repo_name }} {% set scope = repo_metrics.get('_scope', {}) %} {% if scope.get('mode') == 'self_scope' %}
🔒 Scope: self-reflection only. Analysis is locked to the local Git user ({{ scope.filters | join(' / ') }}). Other authors in the repository are not analysed.
{% elif scope.get('mode') == 'team_retro' %}
👥 Scope: consented team retrospective. Caller has explicitly asserted informed consent from every listed author: {% for a in scope.filters %}{{ a }}{% if not loop.last %}, {% endif %}{% endfor %}.
``` ```html {% for author in all_authors | sort %}

👤 {{ author }}

``` ```python class HtmlReporter(BaseReporter): """Generates styled HTML reports from analysis metrics.""" def generate(self, metrics: Dict) -> str: """Generate an HTML report using Jinja2 template.""" template = Template(HTML_TEMPLATE) return template.render(metrics=metrics) ``` Relevant attacker-controlled data sources include: ```python return { "name": os.path.basename(path), "path": path, "active_branch": active_branch, "remotes": [r.name for r in repo.remotes] if repo.remotes else [], } ``` from `src/scanner.py:151-156`, and: ```python author = commit.author.name ``` from analyzer implementations such as `src/analyzers/commit_analyzer.py:56`. ### Technical Analysis The reporter constructs the template directly with `jinja2.Template`. This does not enable automatic HTML escaping. Values inserted with `{{ ... }}` are therefore rendered as raw mark ...[truncated 2224 chars]
Remediation
View remediation
str: environment = Environment( loader=BaseLoader(), autoescape=select_autoescape( enabled_extensions=("html", "xml"), default_for_string=True, default=True, ), ) template = environment.from_string(HTML_TEMPLATE) return template.render(metrics=metrics) ``` 2. Apply `|e` explicitly to security-sensitive values as defense in depth: ```html

📁 {{ repo_name | e }}

👤 {{ author | e }}

{{ a | e }} ``` 3. Avoid applying `join` before escaping individual elements. Escape each filter value independently inside a loop. 4. Treat every value originating from Git metadata, paths, CLI parameters, or Skill parameters as untrusted. 5. Add a restrictive Content Security Policy to generated reports, for example one that blocks scripts and remote resources. 6. Add regression tests using: - `

T09 · Insecure Skill Coding Practices

Warning
Location
src/reporters/pdf_reporter.py:49
Finding

PDF Conversion Processes Untrusted HTML Without a Resource-Access Policy

Content
View full analysis
str: """ Generate a PDF report and write it to a file. Args: metrics: Analysis metrics dict. output_path: Path to write the PDF file. Returns: The output file path. """ # Try HTML-to-PDF engines first for best visual quality html_content = self.generate(metrics) for method in [ self._try_weasyprint, self._try_pdfkit, self._try_xhtml2pdf, ]: try: return method(html_content, output_path) except (ImportError, Exception) as e: logger.debug("PDF method failed: %s", e) continue # Fall back to reportlab (always available) logger.info("Using reportlab for PDF generation") return self._generate_with_reportlab(metrics, output_path) ``` ```python @staticmethod def _try_weasyprint(html_content: str, output_path: str) -> str: from weasyprint import HTML HTML(string=html_content).write_pdf(output_path) logger.info("PDF generated with weasyprint: %s", output_path) return output_path @staticmethod def _try_pdfkit(html_content: str, output_path: str) -> str: import pdfkit pdfkit.from_string(html_content, output_path, options={ "encoding": "UTF-8", "page-size": "A4", "margin-top": "15mm", "margin-bottom": "15mm", }) logger.info("PDF generated with pdfkit: %s", output_path) return output_path @staticmethod def _try_xhtml2pdf(html_content: str, output_path: str) -> str: from xhtml2pdf import pisa with open(output_path, "wb") as f: pisa.CreatePDF(html_content, dest=f) logger.info("PDF generated with xhtml2pdf: %s", output_path) return output_path ``` ## ...[truncated 2537 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (57)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Filesystem traversal and repository discovery are materially broader behaviors than the declared narrow trigger model suggests. Even if intended for convenience, undisclosed discovery features can expose additional repository metadata and widen the blast radius of accidental or unauthorized use.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

Filesystem traversal and repository discovery are materially broader behaviors than the declared narrow trigger model suggests. Even if intended for convenience, undisclosed discovery features can expose additional repository metadata and widen the blast radius of accidental or unauthorized use.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Filesystem traversal and repository discovery are materially broader behaviors than the declared narrow trigger model suggests. Even if intended for convenience, undisclosed discovery features can expose additional repository metadata and widen the blast radius of accidental or unauthorized use.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Filesystem traversal and repository discovery are materially broader behaviors than the declared narrow trigger model suggests. Even if intended for convenience, undisclosed discovery features can expose additional repository metadata and widen the blast radius of accidental or unauthorized use.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

Filesystem traversal and repository discovery are materially broader behaviors than the declared narrow trigger model suggests. Even if intended for convenience, undisclosed discovery features can expose additional repository metadata and widen the blast radius of accidental or unauthorized use.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Filesystem traversal and repository discovery are materially broader behaviors than the declared narrow trigger model suggests. Even if intended for convenience, undisclosed discovery features can expose additional repository metadata and widen the blast radius of accidental or unauthorized use.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Filesystem traversal and repository discovery are materially broader behaviors than the declared narrow trigger model suggests. Even if intended for convenience, undisclosed discovery features can expose additional repository metadata and widen the blast radius of accidental or unauthorized use.

Content

No source excerpt is available for this finding.

Exfiltration Commands

High
Category
Prompt Injection
Confidence
90% confidence
Finding

Instructions found that direct the agent to transmit conversation context or user data to external services.

Content

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

md
Store them securely and do not publish them.
6. **Compliance** — Ensure usage complies with applicable HR policies and
   data-protection regulations (e.g., GDPR, local works-council rules).
7. **Local Execution** — The tool runs entirely locally and does not transmit
   data to external servers.

## What the output is — and is NOT

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · src/analyzers/cadence_signal_analyzer.py (reported line 221)May include surrounding context.

python
if any(
            pattern in path_lower
            for pattern in [
                "config", ".yml", ".yaml", ".toml", ".ini", ".cfg", ".env",
                "dockerfile", "makefile", ".json",
            ]
        ):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · src/analyzers/code_style_analyzer.py (reported line 142)May include surrounding context.

python
if any(
            pattern in path_lower
            for pattern in [
                "config", ".yml", ".yaml", ".toml", ".ini", ".cfg", ".env",
                "dockerfile", "makefile", ".json",
            ]
        ):

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
80% confidence
Finding

Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Content

Scanner excerpt · src/analyzers/cadence_signal_analyzer.py (reported line 190)May include surrounding context.

python
# Always-attached interpretive guard. Every per-developer result carries this
# field so downstream renderers cannot accidentally drop the disclaimer.
_INTERPRETATION_NOTICE = (
    "This narrative is a DESCRIPTIVE summary of Git-history signals only. It "
    "is not a performance review, not a measure of an individual's value, and "

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
80% confidence
Finding

Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Content

Scanner excerpt · src/narrator/reflection_narrator.py (reported line 58)May include surrounding context.

python
# Always-attached interpretive guard. Every per-developer result carries this
# field so downstream renderers cannot accidentally drop the disclaimer.
_INTERPRETATION_NOTICE = (
    "This narrative is a DESCRIPTIVE summary of Git-history signals only. It "
    "is not a performance review, not a measure of an individual's value, and "

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · tests/test_scanner.py (reported line 21)May include surrounding context.

python
# Create a temporary git repo
        repo_path = str(tmp_path / "test_repo")
        os.makedirs(repo_path)
        os.system(f"cd {repo_path} && git init && git commit --allow-empty -m 'init'")

        scanner = RepoScanner()
        repos = scanner.scan_single(repo_path)

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · tests/test_scanner.py (reported line 50)May include surrounding context.

python
# Create a temporary git repo
        repo_path = str(tmp_path / "test_repo")
        os.makedirs(repo_path)
        os.system(f"cd {repo_path} && git init && git commit --allow-empty -m 'init'")

        scanner = RepoScanner()
        repos = scanner.scan_single(repo_path)

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · tests/test_scanner.py (reported line 65)May include surrounding context.

python
# Create a deeply nested repo
        deep_path = tmp_path / "a" / "b" / "c" / "d" / "e" / "f" / "deep_repo"
        os.makedirs(str(deep_path))
        os.system(f"cd {deep_path} && git init && git commit --allow-empty -m 'init'")

        scanner = RepoScanner()
        repos = scanner.scan_directory(str(tmp_path), max_depth=2)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This file is written as a Chinese-only README variant and does not indicate any user language choice within the document. Under the policy rule, forcing a specific language without opt-in can be a locale-policy violation unless the constraint is clearly documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The skill documentation is written as Chinese-only user-facing guidance from the title onward, with no indication that other languages are supported or that the Chinese locale is an intentional, justified regional constraint. Under the language/locale policy rule, forcing a specific language without user opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill advertises and documents capabilities that involve reading repositories, writing reports, and invoking CLI commands, but it does not declare an explicit tool scope such as allowed-tools or permissions. In an agent environment, missing scope declarations can let the runtime grant broader access than intended, increasing the chance of filesystem overreach or shell misuse if the skill is triggered unexpectedly.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
Do NOT trigger on broad phrases like "analyze code", "代码分析",
  "developer evaluation", or "compare developers" — those are too vague
  and risk activating people-data analysis without consent. When the
  request is ambiguous, ask the user to clarify intent and confirm they
  have informed consent from every developer whose history will be read.
---

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

md
Store them securely and do not publish them.
6. **Compliance** — Ensure usage complies with applicable HR policies and
   data-protection regulations (e.g., GDPR, local works-council rules).
7. **Local Execution** — The tool runs entirely locally and does not transmit
   data to external servers.

## What the output is — and is NOT

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The docstrings describe a consent-gated model, but the class itself accepts arbitrary authors input and does not verify that the caller came through the CLI or that consent was established. This creates an enforcement gap where other Python code can directly instantiate an analyzer and target specific contributors' commit history, undermining the privacy and anti-surveillance guarantees the skill claims to provide.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The implementation exposes generic author-targeted Git history filtering via self.authors and substring matching on author name/email, enabling analysis of arbitrary contributors when the class is used as a library. In this skill's context, that is particularly risky because the manifest explicitly limits use to self-reflection or fully consented team retrospectives, so the code-to-policy mismatch can facilitate non-consensual worker monitoring or evaluation.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The docstring asserts that only already-authorized, consented commits are analyzed, but this module contains no local enforcement of that assumption. If the orchestrator or caller misconfigures scope, the analyzer will happily process any commits returned by _get_commits, creating a trust-boundary failure that can expose non-consenting contributors' activity data.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The analyzer emits per-author cadence metrics such as activity ratio, large-gap ratio, and lines-per-active-day keyed by author name. Even without a composite score, these fields are sufficient for downstream consumers to monitor, compare, or rank individuals, so the implementation still enables worker-surveillance use that the surrounding policy text says should be avoided.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This analyzer computes and returns per-author metrics such as bug-fix ratio, revert ratio, large-commit ratio, and average complexity, which are directly attributable to named individuals. Even though comments say the orchestrator limits scope and the output must not be used for evaluation, the code itself exposes individual profiling data that can readily be repurposed for ranking, surveillance, or HR-style assessment if called in a broader context or if upstream guardrails fail.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.