Back to skill

Security audit

Variant Annotation

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent research-oriented variant annotation purpose, but it needs Review because it automatically handles sensitive genetic data and contains unsafe clinical scoring behavior that can overstate pathogenicity when data is missing.

Install only if you are comfortable with variant identifiers being sent to NCBI and with results being stored wherever you choose to write them. Do not use its ACMG classification for diagnosis or treatment; have outputs reviewed by qualified genetics professionals, especially because missing population data can be treated as pathogenic evidence in the current implementation. Prefer running it in an isolated environment, avoid patient-identifying data, and do not provide an NCBI API key unless needed.

Vulnerability Patterns
  • 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
  • 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 (5)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:157
Finding

NCBI API Key Exposed in Request URLs and Duplicated During Retries

Content
View full analysis
Optional[Dict]: """Make NCBI API request with rate limiting and error handling.""" self._rate_limit() if self.api_key: url = f"{url}&api_key={self.api_key}" if "?" in url else f"{url}?api_key={self.api_key}" try: req = urllib.request.Request( url, headers={ "User-Agent": "VariantAnnotator/1.0 (academic research)", "Accept": "application/json" } ) with urllib.request.urlopen(req, timeout=30) as response: return json.loads(response.read().decode('utf-8')) except urllib.error.HTTPError as e: if e.code == 429: time.sleep(1) return self._ncbi_request(url) return None except Exception: return None ``` ### Technical Analysis The NCBI API key is inserted into the complete request URL. Query strings can be retained by HTTP access logs, proxies, debugging systems, monitoring platforms, exception diagnostics, or process instrumentation. Although HTTPS protects the request in transit, it does not prevent the endpoint or trusted intermediary infrastructure from recording the URL. The HTTP 429 handler recursively calls `_ncbi_request(url)` with a URL that already contains the API key. The next invocation appends the same key again. Repeated rate-limit responses therefore create URLs containing multiple copies of the credential and cause unbounded recursion. This can eventually result in oversized URLs, excessive delays, or a `RecursionError`. ### Attack Path 1. A user supplies an NCBI key through `--api-key`. 2. The Skill appends the key to each NCBI request URL. 3. A proxy, monitoring system, exception coll ...[truncated 714 chars]
Remediation
View remediation

other

Warning
Location
scripts/main.py:225
Finding

Potentially Sensitive Genetic Variant Data Is Automatically Transmitted to an External Service

Content
View full analysis
Optional[Dict]: """Query ClinVar database via NCBI E-utilities.""" encoded_query = quote(query) # ESearch to get IDs search_url = ( f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?" f"db=clinvar&term={encoded_query}&retmode=json&retmax=10" ) search_result = self._ncbi_request(search_url) if not search_result or not search_result.get('esearchresult', {}).get('idlist'): return None ids = search_result['esearchresult']['idlist'] if not ids: return None # ESummary to get details id_string = ','.join(ids[:5]) # Limit to top 5 results summary_url = ( f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?" f"db=clinvar&id={id_string}&retmode=json" ) return self._ncbi_request(summary_url) ``` The automatic call is made for every queried variant: ```python # Query ClinVar clinvar_result = self._query_clinvar(variant) ``` ### Technical Analysis Each user-supplied variant identifier, HGVS expression, genomic coordinate, or batch-file entry is encoded into an HTTPS query string and transmitted to the official NCBI E-utilities service. This network access is declared in `SKILL.md` and is necessary for the Skill's online annotation functionality. It is therefore not covert or malicious exfiltration. However, genetic variants can constitute sensitive health or patient information. Query-string values may be retained in remote access logs and trusted intermediary infrastructure. The implementation has no explicit consent gate, privacy confirmation, offline mode, or mechanism for distinguishing public research variants from patient-derived data. Batch processi ...[truncated 1261 chars]
Remediation
View remediation

other

Error
Location
scripts/main.py:290
Finding

Missing Population Frequency Data Is Incorrectly Treated as ACMG PM2 Evidence

Content
View full analysis
max_freq: max_freq = freq if max_freq < 0.0001: criteria.append("PM2") score += self.ACMG_SCORES["PM2"] evidence["PM2"] = f"Absent from population databases (max MAF: {max_freq:.2e})" elif max_freq > 0.05: criteria.append("BA1") score += self.ACMG_SCORES["BA1"] evidence["BA1"] = f"Common variant (MAF: {max_freq:.3f} > 5%)" elif max_freq > 0.01: criteria.append("BS1") score += self.ACMG_SCORES["BS1"] evidence["BS1"] = f"Allele frequency greater than expected ({max_freq:.3f})" ``` The frequency dictionary can contain only unavailable values: ```python allele_freq_dict = { 'gnomad_all': annotation.frequencies.gnomad_genome_all, 'thousand_genomes': annotation.frequencies.thousand_genomes_all } annotation.acmg = self._calculate_acmg_score(clinvar_dict, allele_freq_dict) ``` ### Technical Analysis Population frequency fields default to `None`, but `max_freq` is initialized to `0.0`. The loop ignores `None` values and any numerical zero because the condition begins with `if freq`. If all databases are unavailable, were not queried, failed to respond, or did not provide a parseable result, `max_freq` remains zero. The subsequent condition interprets zero as proof that the variant is absent from population databases and awards ACMG criterion PM2. This conflates two materially different states: - The database was successfully queried and reported absence or a qualifying low frequency. - No usable population evidence was retrieved. In the current implementation, gnomAD is not queried at all despite being advertised, so `gnomad_geno ...[truncated 1415 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding

Unnecessary and Unpinned Third-Party Dependency Expands the Supply-Chain Attack Surface

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
references/clinvar-guide.md:104
Finding

Reference Documentation Recommends Unauthenticated Plaintext FTP Downloads

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (9)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill advertises network, file read, and file write behavior but does not declare any explicit tool scope such as permissions or allowed-tools. This creates an authorization gap where the runtime may grant broader capabilities than reviewers or orchestrators expect, increasing the risk of unintended file access, data exfiltration, or unsafe outbound requests.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The trigger conditions include broad natural-language phrases like mentions of ClinVar, dbSNP, pathogenicity, or clinical significance, which can cause the skill to activate on loosely related conversations. Over-broad invocation is dangerous here because the skill is high-risk, uses network and file capabilities, and produces medically sensitive interpretations that should only run when the user clearly requests variant annotation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This reference document presents ACMG variant-classification guidance in a way that could be used directly for clinical interpretation without any explicit warning that it is informational only and not sufficient for diagnosis or treatment decisions. In the context of a variant-annotation skill, users or downstream agents may over-rely on these rules and produce medical recommendations without clinician review, creating a realistic risk of harmful misclassification.

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 156)May include surrounding context.

md
- **PM3**: For recessive disorders, detected in trans with a pathogenic variant
- **PM4**: Protein length changes as a result of in-frame deletions/insertions in a nonrepeat region or stop-loss variants
- **PM5**: Novel missense change at an amino acid residue where a different missense change determined to be pathogenic has been seen before
- **PM6**: Assumed de novo, but without confirmation of paternity and maternity

### Supporting Pathogenic (PP)
- **PP1**: Cosegregation with disease in multiple affected family members in a gene definitively known to cause the disease

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 · references/acmg-guidelines.md (reported line 39)May include surrounding context.

md
- **PM3**: For recessive disorders, detected in trans with a pathogenic variant
- **PM4**: Protein length changes as a result of in-frame deletions/insertions in a nonrepeat region or stop-loss variants
- **PM5**: Novel missense change at an amino acid residue where a different missense change determined to be pathogenic has been seen before
- **PM6**: Assumed de novo, but without confirmation of paternity and maternity

### Supporting Pathogenic (PP)
- **PP1**: Cosegregation with disease in multiple affected family members in a gene definitively known to cause the disease

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill sends user-supplied variant identifiers and related genetic data to NCBI services without any explicit notice or consent step. Genetic and clinical variant information can be sensitive personal or research data, so silent transmission to a third-party service creates a real privacy risk, especially in regulated or enterprise environments.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The tool can write annotation results containing potentially sensitive genetic and clinical interpretations to an arbitrary user-specified file path without warning about persistence. This increases the chance of accidental long-term storage, leakage through shared filesystems, backups, or insecure permissions, particularly when handling patient or research data.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The line 'AI自主验收状态: 需人工检查' introduces Chinese-language content in otherwise English documentation. Because no language choice, localization note, or justification is provided, this creates a locale/language policy inconsistency.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
60% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
dataclasses

Static analysis

No suspicious patterns detected.