Back to skill

Security audit

tetra-scar

Security checks for vulnerabilities and agentic risk

Overview

The skill is not clearly malicious, but it bundles under-described repository scanning and CI audit capabilities alongside persistent agent-memory controls with real scoping and safety issues.

Review this carefully before installing. Use only in a sandbox or trusted repository, pin installer and action versions, avoid passing untrusted GitHub Action inputs, restrict scan paths, do not scan repositories containing attacker-controlled symlinks, and treat exported memory/training data as potentially sensitive.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
action.yml:38
Finding

GitHub Action Inputs Can Be Injected into Shell and Python Code

Content
View full analysis
/tmp/scar_audit_result.json 2>&1 || true ``` ```yaml run: | FAIL_ON="${{ inputs.fail-on }}" python3 -c " import json, sys d=json.load(open('/tmp/scar_audit_result.json')) levels=['LOW','MEDIUM','HIGH','CRITICAL'] threshold=levels.index('$FAIL_ON') if '$FAIL_ON' in levels else 3 for f in d.get('findings',[]): sev=f.get('severity','') if sev in levels and levels.index(sev) >= threshold: print(f'FAIL: {sev} finding — {f[\"description\"]}') sys.exit(1) print('PASS: No findings at or above $FAIL_ON severity') " ``` ### Technical Analysis GitHub Actions expressions are interpolated into the generated shell script before Bash parses it. Placing `${{ inputs.path }}` inside double quotes does not safely treat it as inert data: shell constructs introduced by the interpolated value, such as command substitution, can become executable syntax. The `fail-on` input is exposed through two unsafe contexts: 1. It is interpolated into a Bash assignment. 2. It is subsequently embedded inside Python source code passed to `python3 -c`. A malicious value containing quote characters and Python syntax can terminate the intended Python string and append attacker-controlled statements. The action does not validate either input before constructing executable shell or Python code. Exploitation requires the attacker to influence action inputs, such as through an unsafe reusable workflow, workflow-dispatch plumbing, or another workflow that derives these values from untrusted metadata. ### Attack Path 1. A workflow invokes the composite action and passes an attacker-influenced value to `path` or `fail-on`. 2. GitHub ...[truncated 1051 chars]
Remediation
View remediation
"$RUNNER_TEMP/scar_audit_result.json" ``` - Read and validate `fail-on` as data: ```yaml env: FAIL_ON: ${{ inputs.fail-on }} run: | python3 - <<'PY' import json import os import sys levels = ["LOW", "MEDIUM", "HIGH", "CRITICAL"] fail_on = os.environ["FAIL_ON"] if fail_on not in levels: raise SystemExit(f"Invalid fail-on value: {fail_on!r}") # Continue using fail_on as a value, not generated source. PY ``` - Validate `path` against the intended workspace root. - Avoid constructing Python programs with shell-expanded values. - Add tests containing quotes, command substitutions, newlines, and shell metacharacters in every action input. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
action.yml:38
Finding

Audit Failures Are Suppressed and Can Produce Misleading Successful Results

Content
View full analysis
/tmp/scar_audit_result.json 2>&1 || true FINDINGS=$(python3 -c "import json; d=json.load(open('/tmp/scar_audit_result.json')); print(len(d.get('findings',[])))" 2>/dev/null || echo "0") SCORE=$(python3 -c " ``` The score calculation also provides a perfect-score fallback: ```yaml " 2>/dev/null || echo "100") ``` The human-readable invocation is similarly ignored: ```yaml python3 ${{ github.action_path }}/scar_audit.py --local "${{ inputs.path }}" 2>&1 || true ``` ### Technical Analysis The action discards failures from the scanner with `|| true`. It then suppresses JSON parsing errors and substitutes security-positive defaults: - Failed finding extraction becomes `0`. - Failed score calculation becomes `100`. - Failed report generation does not fail the step. This conflates “the scan completed and found nothing” with “the scanner failed or returned malformed output.” The resulting job summary can therefore report a perfect safety score even when no valid security scan occurred. The later threshold step may fail when it attempts to parse malformed JSON, but that step is skipped when `fail-on` is `NONE`. Even when the job ultimately fails, the generated score and summary remain misleading and the behavior is inconsistent rather than reliably fail-closed. ### Attack Path 1. An attacker or malformed repository condition causes the scanner to fail, hang until terminated, or emit invalid JSON. 2. `|| true` converts the scanner failure into a successful shell command. 3. JSON parsing fails. 4. The fallback paths report zero findings and a score of 100. 5. If threshold enforcement is disabled with `fail-on: NONE`, the workflow completes without a va ...[truncated 580 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scar_audit.py:81
Finding

Repository Scanner Can Follow File Symlinks Outside the Requested Scan Root

Content
View full analysis
list[dict]: """Scan all source files in a directory.""" if extensions is None: extensions = {".py", ".js", ".ts", ".jsx", ".tsx", ".sh", ".yaml", ".yml"} root = Path(path) all_findings = [] files_scanned = 0 for f in root.rglob("*"): if f.suffix not in extensions: continue if any(skip in str(f) for skip in ["node_modules", ".git", "__pycache__", ".venv", "venv"]): continue findings = scan_file(f) all_findings.extend(findings) files_scanned += 1 return all_findings, files_scanned ``` The candidate is subsequently opened without symlink or containment checks: ```python content = filepath.read_text(encoding="utf-8", errors="ignore") ``` ### Technical Analysis The scanner discovers filesystem entries with `Path.rglob()` but does not reject symbolic links. It also does not resolve candidate paths and verify that the resolved target remains beneath the requested root. A repository can therefore contain a file symlink with a scanned extension, such as `external.py`, whose target is outside the repository. When `scan_file()` calls `read_text()`, the operating system follows that symlink. The scanner's JSON output includes the raw matched substring under the `match` property. Consequently, external file content matching one of the audit regular expressions can be returned in generated output rather than merely being accessed internally. Exploitation is limited to files readable by the scanner process and to content selected by the scanner's regular-expression patterns. ### Attack Path 1. An attacker commits or creates a symlink named with a supported extension, such a ...[truncated 962 chars]
Remediation
View remediation

T02 · Agent Memory Poisoning

Warning
Location
tetra_scar.py:26
Finding

Persistent Scar Rules Are Trusted Without Integrity or Authorization Controls

Content
View full analysis
Path: """Resolve memory directory. Creates if not exists.""" d = Path(memory_dir) if memory_dir else DEFAULT_MEMORY_DIR d.mkdir(parents=True, exist_ok=True) return d ``` Scar data is loaded without authentication or integrity verification: ```python def _read_jsonl(filepath: Path) -> list[dict]: """Read a JSONL file, skipping malformed lines.""" if not filepath.exists(): return [] entries = [] with open(filepath, encoding="utf-8") as f: for line in f: line = line.strip() if not line: continue try: entries.append(json.loads(line)) except json.JSONDecodeError: continue return entries ``` The persistent records directly influence future decisions: ```python for scar in scars: never = scar.get("never_again", "") if not never: continue keywords = _extract_keywords(never) if len(keywords) < 2: continue matches = [kw for kw in keywords if kw.lower() in task_lower] threshold = max(min_matches, len(keywords) * threshold_ratio) if len(matches) >= threshold: return ( f"scar collision: '{never[:60]}' " f"(matched: {', '.join(matches[:5])})" ) ``` ### Technical Analysis The default persistent memory is stored under the current working directory, which commonly places it inside a project workspace accessible to other tools, repository code, or collaborating processes. Although the documentation describes scars as immutable, the implementation only appends during ...[truncated 1887 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
README.md:27
Finding

Documented Installation Executes an Unpinned Third-Party Package

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • 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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

If the skill actually performs repository cloning, broad source scanning, regex-based analysis, and audit report generation while presenting itself as a memory/reflex tool, the deception materially changes its risk profile. In the context of an agent skill, undeclared repo access, subprocess/git execution, and filesystem-wide inspection can expose sensitive code and trigger unintended actions under the guise of a safer-looking feature set.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

If the skill actually performs repository cloning, broad source scanning, regex-based analysis, and audit report generation while presenting itself as a memory/reflex tool, the deception materially changes its risk profile. In the context of an agent skill, undeclared repo access, subprocess/git execution, and filesystem-wide inspection can expose sensitive code and trigger unintended actions under the guise of a safer-looking feature set.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

If the skill actually performs repository cloning, broad source scanning, regex-based analysis, and audit report generation while presenting itself as a memory/reflex tool, the deception materially changes its risk profile. In the context of an agent skill, undeclared repo access, subprocess/git execution, and filesystem-wide inspection can expose sensitive code and trigger unintended actions under the guise of a safer-looking feature set.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The implementation materially differs from the manifest: instead of scar memory, reflex blocking, or decision-trace persistence, it performs repository scanning and report generation. This kind of capability mismatch is dangerous because users or higher-level agents may grant permissions, trust, or workflow placement based on the declared safety function while the code performs different network-enabled actions.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding

The README instructs users to run npx clawhub@latest install ..., which fetches and executes the latest published package version at install time. Using an unpinned version in an execution path creates a supply-chain risk: a compromised maintainer account, malicious release, or breaking change could cause arbitrary code execution on the user's machine or CI environment.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill declares executable capabilities via Python examples and integration code, and the analyzer reports file read/write, network, and shell-like behavior, but the manifest does not declare any tool scope such as permissions or allowed-tools. That creates an unsafe trust boundary: a host agent may grant broader access than users expect, making file modification, command execution, or network access less transparent and harder to constrain.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The provided skill-manifest context says tetra-scar is for agent memory, scars, reflex arcs, and decision traces, but this file defines a GitHub Action named 'tetra-scar-audit' that scans code for agent failure patterns and publishes audit scores. The implementation behavior is an audit/reporting tool rather than a memory or failure-retention mechanism, so the actual capability does not match the stated tetra-scar purpose.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · examples/example_incident_response.py (reported line 36)May include surrounding context.

python
"post_with_key": (
        "Send bearer token via curl: "
        "curl -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.secret' "
        "https://api.example.com/data"
    ),
}

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The docstring markets the tool as 'tetra-scar analysis' and 'the product' while the code is only a simple regex-based scanner. Overstated security claims can cause unsafe reliance on incomplete analysis, leading users to miss real issues or overtrust the output in automated pipelines.

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 · scar_audit.py (reported line 70)May include surrounding context.

python
"delete_without_confirm": {
        "pattern": r"(shutil\.rmtree|os\.remove|\.delete\(\))",
        "severity": "HIGH",
        "description": "Destructive operation without confirmation",
        "remedy": "Add confirmation step or dry-run mode before destructive ops.",
    },
}

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The code clones a user-supplied repository URL over the network without meaningful disclosure, restriction, or validation. In agentic settings, this can be abused to trigger unexpected outbound network access to attacker-controlled endpoints, violate policy boundaries, or fetch hostile content into the local environment for subsequent processing.

Content

No source excerpt is available for this finding.

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 · scar_audit.py (reported line 173)May include surrounding context.

python
"""Clone a GitHub repo to temp directory."""
    import tempfile
    tmpdir = tempfile.mkdtemp(prefix="scar_audit_")
    subprocess.run(["git", "clone", "--depth", "1", url, tmpdir],
                   capture_output=True, timeout=60)
    return tmpdir

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The top-level docstring describes only two layers of memory: scars and narrative. However, the file also implements a delayed verification subsystem and a full decision-trace layer with LoRA training-data export, which goes beyond and contradicts the documented architecture summary.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The keyword extractor is explicitly limited to English words and Japanese kanji/katakana, as stated in the docstring and implemented in the regex patterns. This imposes a language/locale constraint in natural language handling without offering user opt-in, fallback, or justification for excluding other languages.

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 · tetra_scar.py (reported line 196)May include surrounding context.

python
_DANGEROUS_OPS = frozenset([
    "rm -rf", "drop table", "force push", "reset --hard",
    "全削除", "全ファイル", "truncate table", "format disk",
    "sudo rm", "del /f /s",
])

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

export_training_data serializes scars and decision traces directly to a JSONL file, which can include sensitive operational history, failures, reasoning, or user data. In an agent-memory skill, that context makes the issue more dangerous because the stored content is specifically intended to preserve past decisions and mistakes, increasing the chance of confidential data being persisted and later exposed.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest describes scar memory, narrative memory, and decision traces for reflex blocking and learning from failures. The delayed verification scheduler/runner is an extra persistence workflow for future review of actions, which is not reflected in the stated skill purpose and is not an obvious requirement of the three-layer memory design.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.