Back to skill

Security audit

employee-skills-importer

Security checks for vulnerabilities and agentic risk

Overview

The skill has a legitimate import purpose, but it handles employee data and generates live database-changing SQL with unsafe and under-controlled identity matching.

Review this skill before installing or using it against real employee data. Use a staging database and least-privileged Supabase credentials, manually inspect all generated SQL, require explicit approval for every fuzzy employee-name match, and ensure all CSV-derived text is safely escaped or imported through parameterized database code before running anything in production.

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

Error
Location
SKILL.md:49
Finding
SQL Injection in Generated Database Import Scripts## Vulnerability Details **File Location**: `SKILL.md:49-55`, `SKILL.md:68-73`, `SKILL.md:87-95`, `SKILL.md:200-219` **Vulnerability Type**: Untrusted CSV values interpolated into executable SQL **Risk Level**: High ### Vulnerable Code Snippets Category names from the CSV are inserted directly into SQL string literals: ```sql INSERT INTO skill_categories (name) VALUES ('Category1'), ('Category2'), ('Category3') ON CONFLICT (name) DO NOTHING; ``` Skill and category names are inserted in the same unsafe manner: ```sql INSERT INTO skills (name, category_id) VALUES ('C#', (SELECT id FROM skill_categories WHERE name = '.NET')), ('JavaScript', (SELECT id FROM skill_categories WHERE name = 'Front-end')) ON CONFLICT (name) DO NOTHING; ``` Employee names and skill names are also placed directly into generated queries: ```sql INSERT INTO employee_skills (employee_id, skill_id, years_of_experience) VALUES ( (SELECT id FROM employees WHERE TRIM(first_name) = 'John' AND TRIM(last_name) = 'Doe'), (SELECT id FROM skills WHERE name = 'C#'), 5 ) ON CONFLICT (employee_id, skill_id) DO UPDATE SET years_of_experience = EXCLUDED.years_of_experience; ``` The generation workflow explicitly directs the agent to create SQL using corrected names without requiring SQL-literal escaping: ```text - Generate INSERT statements using corrected employee names - Save SQL file and report to outputs directory - Present both files to user ``` ### Technical Analysis Category names, skill names, and employee names originate from an uploaded CSV and are therefore untrusted. The documented generation process embeds those values between single quotes without requiring parameterization or escaping embedded apostrophes. An attacker-controlled value can terminate its SQL string literal and append additional SQL syntax. The resulting payload does not execute while the CSV is parsed, but it becomes active when the user executes the generated script in the Supabase SQL edit ...[truncated 1386 chars]
Remediation
## Remediation Suggestions 1. Prefer parameterized inserts through a trusted PostgreSQL or Supabase client instead of generating executable SQL containing raw CSV values. 2. If SQL files must be generated, implement one centralized PostgreSQL literal serializer that replaces every single quote with two single quotes before placing text into a literal. 3. Apply that serializer to all category names, skill names, employee names, comments, and any other CSV-derived text. 4. Parse `years_of_experience` using a strict finite-number parser and emit only a canonical numeric representation. Reject nonnumeric values rather than copying them into SQL. 5. Validate generated scripts with a PostgreSQL-aware SQL parser before presenting them to the user. 6. Clearly mark generated scripts as derived from untrusted input and require review before execution. 7. Execute imports with a least-privileged database role restricted to the four intended tables. 8. Add regression tests for ordinary apostrophes, such as `O'Brien`, and adversarial inputs containing quotes, semicolons, comments, and statement terminators.

other

Warning
Location
SKILL.md:165
Finding
Automatic Fuzzy Name Matching Can Associate Skills with the Wrong Employee## Vulnerability Details **File Location**: `SKILL.md:165-178`, `SKILL.md:282-289` **Vulnerability Type**: Unsafe identity resolution through automatic fuzzy matching **Risk Level**: Medium ### Vulnerable Code Snippet ```text 5. **Generate Script 3: Employee Skills** - Parse employee rows - **VALIDATE: Compare all CSV employees against database using exact matching** - **FUZZY MATCH: For non-exact matches, find closest database employee using similarity algorithm** - Calculate similarity score for first_name and last_name separately - If combined similarity is above threshold (e.g., 85%), automatically use database name - Track all automatic corrections for reporting - **CORRECT: Replace CSV names with database names for matched employees** - **FILTER: Skip employees with no close match found** - **DEDUPLICATE: Remove duplicates by (employee, skill), keeping highest years value** - Generate INSERT statements using corrected employee names ``` ```text ### Name Matching Algorithm The skill uses the following approach: 1. Try exact match first (first_name AND last_name) 2. If no exact match, calculate similarity score using: - Levenshtein distance or similar algorithm - Handles common variations: "Victoriia"↔"Viktoriia", "Karasyov"↔"Karasov" 3. If similarity > 83% threshold, accept as match 4. If multiple close matches found, pick the closest one 5. If no close match, skip the employee 6. Always trim whitespace from both CSV and database names 7. Use TRIM() in SQL queries to match records with extra spaces in database ``` ### Technical Analysis The skill treats first and last names as identity keys and automatically replaces nonmatching CSV names with the closest database name when a similarity threshold is exceeded. Names are not unique identifiers, and small spelling distance does not establish that two records represent the same person. The instructions also direct the implementation to select the closest candidat ...[truncated 1479 chars]
Remediation
## Remediation Suggestions 1. Use a stable, unique employee identifier in the CSV, such as an employee UUID or organization-issued employee number. 2. Do not automatically accept fuzzy matches. Require explicit user confirmation for every non-exact match. 3. Reject ambiguous matches when multiple candidates are close, even if one candidate has the highest score. 4. Require a minimum separation between the best and second-best scores in addition to a conservative acceptance threshold. 5. Normalize Unicode, case, and whitespace before exact matching, but treat normalization separately from identity inference. 6. Produce a dry-run mapping report showing the source identity, proposed database identity, matching method, and confidence score. 7. Preserve an audit log of approved corrections. 8. Add tests covering duplicate names, transliteration variants, short names, and multiple candidates with similar scores.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (6)

Natural-Language Policy Violations

High
Confidence
94% confidence
Finding
The skill directs automatic correction of employee names using fuzzy matching thresholds without requiring user review or approval. In this context, that can misidentify employees and generate SQL that writes skill records to the wrong person, causing integrity issues in HR-related data and potentially exposing or corrupting personal records.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The README instructs users to execute generated SQL against a live Supabase database but does not tell them to review or validate the SQL first. Because the skill parses untrusted CSV input and generates statements that affect multiple tables, omissions or prompt/format manipulation could lead to unintended inserts, bad mappings, or corruption of production data if users execute the output blindly.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The README says the skill checks the database by connecting to Supabase, but it does not explain what data may be transmitted, what access is used, or the privacy implications of uploading employee-related CSV data for processing. In this context, the data includes employee identities and skills, so lack of disclosure can cause unintentional exposure of sensitive HR information and unsafe assumptions about where data flows.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill is designed to access the employees table and process personal data such as first and last names, including fuzzy matching and automatic correction, but the description does not clearly disclose that personal employee data will be read and transformed. This creates a transparency and privacy risk because users may invoke the skill without understanding the extent of data access and identity processing involved.

Missing User Warnings

Low
Confidence
87% confidence
Finding
This markdown file documents SQL scripts that write to the database, and L085 states that conflicts will update existing years_of_experience values. While the notes mention the update behavior later, there is no clear user warning that running the script changes existing employee data, which is a data-affecting operation.

Intent-Code Divergence

Low
Confidence
76% confidence
Finding
The Notes section states that skills with 0 or empty experience are skipped. However, the example output includes low nonzero values and provides no example of skipped zero values, making the documentation potentially misleading about actual output behavior; if zero values are really skipped, this note is not evidenced here, and if they are not skipped, it is contradictory.

Static analysis

No suspicious patterns detected.