Back to skill

Security audit

ere

Security checks for vulnerabilities and agentic risk

Overview

This is mostly a coherent writing-refinement skill, but users should review it because its documented analysis workflow stores submitted text in predictable shared temporary files.

Install only if you are comfortable reviewing the workflow first. Avoid using it on confidential drafts until the temporary-file commands are changed to use a private mktemp directory with cleanup, and treat its fact-preservation claims as editorial guidance that still needs human review.

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
SKILL.md:189
Finding

Predictable Shared Temporary Files Permit Symlink-Based File Overwrite

Content
View full analysis
/tmp/ere_original.txt echo "$REFINED" > /tmp/ere_refined.txt # Analyze / analisar python3 scripts/ere.py analyze /tmp/ere_refined.txt python3 scripts/ere.py diff /tmp/ere_original.txt /tmp/ere_refined.txt ``` ### Technical Analysis The Skill instructs the agent to store user-provided text in two fixed paths under the globally shared `/tmp` directory. These paths are predictable and are opened through ordinary shell redirection, which follows symbolic links. A local attacker can create either path as a symbolic link to another file writable by the account running the agent. When the workflow executes, the redirection overwrites the symlink target with the original or refined text. The files are also not explicitly created with restrictive permissions and are not deleted after analysis. Depending on the process umask and host configuration, this can expose potentially sensitive submitted content to other local processes. Concurrent executions can also overwrite one another's data or analyze content from the wrong run. ### Attack Path 1. A local attacker determines that the ERE workflow uses `/tmp/ere_original.txt` and `/tmp/ere_refined.txt`. 2. The attacker creates one of these paths as a symbolic link to a file writable by the agent account: ```bash ln -s /path/to/agent-writable-file /tmp/ere_original.txt ``` 3. A user invokes ERE refinement with quantitative analysis. 4. The agent follows the documented command: ```bash echo "$ORIGINAL" > /tmp/ere_original.txt ``` 5. Shell redirection follows the symbolic link and overwrites the target with user-supplied text. 6. Alternatively, another local process can read, replace, or race the temporary files before the analysis commands execut ...[truncated 718 chars]
Remediation
View remediation
"$tmpdir/original.txt" printf '%s' "$REFINED" > "$tmpdir/refined.txt" python3 scripts/ere.py analyze "$tmpdir/refined.txt" python3 scripts/ere.py diff \ "$tmpdir/original.txt" \ "$tmpdir/refined.txt" ``` Additional hardening measures: 1. Use `printf '%s'` rather than `echo` so option-like text and escape sequences are not interpreted inconsistently. 2. Set a restrictive umask, such as `umask 077`, before creating files. 3. Keep all generated paths quoted. 4. Register cleanup before writing sensitive data. 5. Avoid retaining input after analysis unless the user explicitly requests persistence. 6. If implemented directly in Python, use `tempfile.TemporaryDirectory()` or securely opened files rather than constructing names manually. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/ere.py:25
Finding

Unvalidated Profile Name Allows Directory Traversal and Unintended YAML File Reads

Content
View full analysis
dict: """Load editorial profile from YAML (simple subset parser).""" profile_file = PROFILES_DIR / f"{name}.yaml" if not profile_file.exists(): profile_file = PROFILES_DIR / "default.yaml" if not profile_file.exists(): return _default_profile() ``` User-controlled command-line input: ```python if command == "profile": name = sys.argv[2] if len(sys.argv) > 2 else "default" profile = load_profile(name) print(json.dumps(profile, indent=2, ensure_ascii=False)) ``` ### Technical Analysis The `profile` command accepts a profile name from `sys.argv[2]` and interpolates it directly into a filesystem path: ```python PROFILES_DIR / f"{name}.yaml" ``` The name is not restricted to a simple profile identifier, and the resolved path is not checked to ensure that it remains inside `PROFILES_DIR`. A name containing traversal components such as `../` can therefore escape the intended profile directory. If the escaped path identifies an existing readable file with the automatically appended `.yaml` extension, the loader reads and parses it. The resulting values are printed as JSON by the `profile` command. The fallback to `default.yaml` occurs only when the constructed path does not exist. It does not protect an existing file outside the profile directory. ### Attack Path 1. An attacker supplies a profile argument containing parent-directory components, for example: ```bash python3 scripts/ere.py profile ../../private/config ``` 2. The application constructs a path equivalent to: ```text profiles/../../private/config.yaml ``` 3. If that file exists and is readable by the process, `profile_file.exists()` succeeds. 4. `read_text()` loads the ext ...[truncated 932 chars]
Remediation
View remediation
dict: """Load an editorial profile from the profiles directory.""" if not re.fullmatch(r"[A-Za-z0-9_-]+", name): raise ValueError("Invalid profile name") profiles_root = PROFILES_DIR.resolve() profile_file = (profiles_root / f"{name}.yaml").resolve() if profile_file.parent != profiles_root: raise ValueError("Profile path escapes profiles directory") if not profile_file.is_file(): profile_file = profiles_root / "default.yaml" if not profile_file.is_file(): return _default_profile() # Continue parsing the validated file. ``` For a fixed set of supported profiles, an explicit allowlist is preferable: ```python ALLOWED_PROFILES = { "default", "technical", "corporate", "creative", "minimal", } if name not in ALLOWED_PROFILES: raise ValueError(f"Unknown profile: {name}") ``` Additional hardening measures: 1. Reject absolute paths, path separators, `.` components, and `..` components. 2. Resolve the candidate path before opening it. 3. Confirm that the resolved parent is exactly the profiles directory. 4. Use `is_file()` rather than only `exists()`. 5. Return a clear error for invalid names instead of silently falling back, reducing ambiguity and making misuse visible. 6. Add regression tests for values such as `../config`, `../../private/settings`, absolute paths, and valid profile names. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (35)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill is presented as a transformation engine that preserves facts during rewriting, but the described executable behavior appears limited to analysis, diffing, and scoring. This mismatch can mislead users into trusting outputs or workflows that do not actually provide the claimed safeguards, causing integrity failures in editorial or compliance-sensitive use cases.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/ere.py analyze /tmp/ere_refined.txt

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/ere.py analyze /tmp/ere_refined.txt

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/ere.py analyze /tmp/ere_refined.txt

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/ere.py analyze /tmp/ere_refined.txt

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| Hermes Agent | `SKILL.md` (metadata.hermes) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| Hermes Agent | `SKILL.md` (metadata.hermes) |

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The trigger phrases are generic editorial requests such as 'refine this text' and 'humanize', which can overlap with ordinary user instructions and cause the skill to activate without clear consent or scope checks. That creates a prompt-scope risk: the agent may apply transformation behavior in situations where the user intended a narrower edit, potentially altering protected content or bypassing workflow expectations.

Content

No source excerpt is available for this finding.

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
85% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

Scanner excerpt · README.md (reported line 45)May include surrounding context.

Claude Code

bash
mkdir -p .claude/skills/ere
cp -r ere/* .claude/skills/ere/

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The README shows activation-style phrases such as "ERE: refine and analyze" and "ERE: refine this text" but does not define whether these are the only accepted triggers, what contexts they apply in, or any negative examples. In a markdown skill description, this can create ambiguous invocation boundaries and increase the chance of unintended activation from ordinary editing requests.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

Policy-violation checks apply to all file types, including markdown. The description states the skill works in English and Portuguese (pt-BR) only, which is a language/locale constraint, but it does not present this as an explicit user opt-in or justify why the locale limitation is required.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The 'deep rewrite' level says it preserves only facts and entities, which directly conflicts with the skill's broader promises to never omit information and to preserve quotes and all factual content. Conflicting rules increase the chance of destructive rewriting, especially when users choose higher rewrite levels expecting safe editorial refinement.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The example output introduces interpretive or embellished content and omits exact preservation, despite repeated claims that facts, entities, and quotes must remain unchanged and nothing may be added. Users may rely on these guarantees for factual or quoted content and unknowingly publish altered meaning or unsupported details.

Content

No source excerpt is available for this finding.

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
80% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

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

md
|--------|--------------|
| Hermes Agent | `SKILL.md` (metadata.hermes) |
| OpenClaw | `SKILL.md` (metadata.openclaw) |
| Claude Code | `.claude/skills/ere/SKILL.md` + `CLAUDE.md` |
| Codex | `.agents/skills/ere/SKILL.md` + `AGENTS.md` |

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
80% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

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

md
|--------|--------------|
| Hermes Agent | `SKILL.md` (metadata.hermes) |
| OpenClaw | `SKILL.md` (metadata.openclaw) |
| Claude Code | `.claude/skills/ere/SKILL.md` + `CLAUDE.md` |
| Codex | `.agents/skills/ere/SKILL.md` + `AGENTS.md` |

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The description states the skill operates in 'English + Portuguese pt-BR', which is a natural-language locale constraint. In this manifest, there is no indication that users can choose another language or opt in to the pt-BR locale, so it appears to impose a language policy by default.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The configuration sets language: pt-BR as the default output language, and the additional profiles also hard-code pt-BR. Per the policy, forcing a specific language/locale without offering user choice or documenting a justified regional constraint is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The technical profile explicitly fixes language to pt-BR with no indication that users can choose another language. This constitutes a locale restriction that is not clearly justified in the file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The corporate profile explicitly sets language: pt-BR and does not indicate any user choice or justified locale limitation. This can force users into a specific language contrary to the stated policy.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The creative profile fixes the language to pt-BR without offering user selection. The policy requires either opt-in/user choice or a documented reason for the locale constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The minimal profile sets language: pt-BR and does not present this as optional or justified. This is a natural-language locale restriction lacking opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file contains a natural-language/config example that hardcodes language: "pt-BR" in the refinement request. Under the language/locale policy, forcing a specific language or locale without user opt-in can be a policy violation unless the constraint is clearly justified or optionality is documented.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The file is written as a normative catalog of preferred wording and style in Portuguese, and line L04 states that the system detects and removes these patterns during refinement. There is no indication that users may choose another language or locale, so the skill appears to enforce a specific language/style policy by default.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The text states that the focus is on what 'um editor de texto pt-BR deve fazer', which frames the skill as enforcing Brazilian Portuguese behavior. Because the file does not indicate that language selection is optional or limited to a clearly region-specific context, this is a natural-language locale policy concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.