Back to skill

Security audit

Cite Holmes — Deep Research × Hallucination-Free Citations

Security checks for vulnerabilities and agentic risk

Overview

This research helper needs review because citation links can reach private services, offline mode can still transmit data, and verification results can overstate certainty.

Use a reviewed, fixed version in an environment that blocks private-network access. Independently check important citations and retraction status. Disable caching and use --workers 1 when comparing conflicting references. For confidential material, enforce network blocking externally; --offline alone is insufficient when optional model endpoints are configured.

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 (1)

T09 · Insecure Skill Coding Practices

Warning
Location
.
Finding

Unchecked redirects allow citation URLs to reach private-network services

Content
View full analysis

Impact

An attacker can cause otherwise-blocked internal HTTP requests and obtain limited reachability/status information through the verification result. Internal endpoints with side effects on HEAD or GET can also be invoked. This code path does not return response bodies, so arbitrary internal-data disclosure is not established.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (45)

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The supplied code has a materially different primary purpose from the declared research and citation-checking functionality. It validates skill metadata and prints packaging guidance; it does not search literature, query citation registries, verify identifiers or retractions, or export bibliographies. Metadata validation could be a development utility within a larger research skill, but this chunk contains no connection to the declared workflow. No network access, file modification, or code execution beyond the validator itself is evident.

Content

No source excerpt is available for this finding.

PubMed verification paths can mark references verified without performing the promised retraction check.

High
Category
Excessive Agency
Confidence
99% confidence
Finding

Successful PubMed reverse and locator lookups return verified before running retraction checks, and the regular PMID-only path also lacks equivalent retraction screening. Retracted papers can therefore receive a clean-looking verdict and enter verified-only exports, which is especially consequential in this skill's medical and submission workflows.

Content

No source excerpt is available for this finding.

References can receive a verified verdict without successful registry verification.

High
Category
Excessive Agency
Confidence
99% confidence
Finding

The final verdict gate assigns verified based on source tier and field completeness without requiring successful registry metadata verification. Failed or skipped DOI/PMID checks can therefore leave a reachable citation eligible for verified, undermining the skill's central authenticity guarantee and potentially laundering fabricated references.

Content

No source excerpt is available for this finding.

Disk-cache hits reuse stale semantic judgments instead of evaluating the current citation's semantic audit.

High
Category
Excessive Agency
Confidence
99% confidence
Finding

The disk-cache key excludes semantic input, but a cache hit returns the previous semantic_audit instead of rebuilding it from the current citation. A newly supplied contradicted or not_in_source judgment can consequently be replaced by an older favorable judgment, bypassing the subsequent semantic cap and retaining verified status.

Content

No source excerpt is available for this finding.

Parallel result reuse contradicts the documented independent verification of differing citation claims.

High
Category
Excessive Agency
Confidence
100% confidence
Finding

Parallel work deduplication keys only on an identifier or normalized URL, although verification also depends on the claimed title, authors, source, and other fields. Followers inherit the leader's result and even its displayed citation fields, so conflicting claims can disappear rather than receive independent verification; duplicate downgrading does not restore the lost evidence.

Content

No source excerpt is available for this finding.

References can receive a verified verdict even when registry verification failed or never occurred.

High
Category
Excessive Agency
Confidence
99% confidence
Finding

The final verdict logic can assign verified based on reachability, source tier, and field completeness without requiring successful metadata verification. Registry failures therefore fail open, and attacker-supplied tier values or loosely matched authoritative-looking hostnames further weaken the gate; this is particularly dangerous for a skill whose core purpose is detecting fabricated citations.

Content

No source excerpt is available for this finding.

Persistent-cache hits reuse stale semantic judgments and can bypass a current negative semantic assessment.

High
Category
Excessive Agency
Confidence
100% confidence
Finding

The persistent cache key excludes semantic input, but cached payloads retain semantic and semantic_audit fields. On a cache hit, a new contradicted or not_in_source assessment can be replaced by the previous assessment, so apply_semantic_cap fails to enforce the current negative evidence.

Content

No source excerpt is available for this finding.

Parallel caching substitutes one reference's identity and verdict for other references sharing an identifier.

High
Category
Excessive Agency
Confidence
100% confidence
Finding

Parallel deduplication keys references only by an identifier and copies the leader's complete result to followers without validating their distinct titles, authors, sources, or secondary identifiers. A fabricated reference sharing a real identifier can consequently disappear behind another reference's identity and judgment; later duplicate marking may downgrade it to partial but does not recover the missing mismatch detection.

Content

No source excerpt is available for this finding.

MCP server referenced without pinned version: 'npx skills'.

Medium
Category
MCP Rug Pull
Confidence
96% confidence
Finding

The documented npx skills add docsor1212/cite-holmes command executes an unpinned npm CLI and installs skill content from an unpinned repository reference. A compromised future release or upstream repository could introduce code or agent instructions that run with the user's permissions; this is a supply-chain risk, not evidence of malicious intent or an MCP-specific flaw.

Content

No source excerpt is available for this finding.

MCP server referenced without pinned version: 'npx skills'.

Medium
Category
MCP Rug Pull
Confidence
96% confidence
Finding

This repeated installation example has the same unpinned CLI and repository supply-chain exposure as the earlier command. Although it is ordinary installation guidance rather than an instruction to bypass security, following it can execute a subsequently compromised npm release and introduce unreviewed skill instructions.

Content

No source excerpt is available for this finding.

Skill declares no tool scope ('permissions' or 'allowed-tools') but code capabilities were detected: env, file_read, file_write, network.

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.

MCP server referenced without pinned version: 'uvx from'.

Medium
Category
MCP Rug Pull
Confidence
99% confidence
Finding

Although the match is in a comment, the associated uvx command installs and executes code from a GitHub repository without an immutable revision. The MCP client configurations repeat this mutable source, so a compromised repository or malicious upstream change could execute code with the client's permissions, potentially accessing local research, files, or available credentials.

Content

No source excerpt is available for this finding.

MCP server referenced without pinned version: 'uvx from'.

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding

Running uvx against a local checkout is not inherently an unpinned remote installation, but the documented workflow first clones the repository's current default branch without checking out a reviewed revision. Following the complete workflow therefore executes mutable upstream code, creating the same supply-chain exposure at checkout time; the README alone does not demonstrate malicious behavior.

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 · mcp/verify_refs.py (reported line 560)May include surrounding context.

python
if len(cn) >= 12 and (_OPTS.get("openalex_key") or ""):
        try:
            q = quote(claimed.strip(), safe="")
            url = (f"https://api.openalex.org/works?search=%7Bq%7D&per-page=1"
                   f"&select=display_name&api_key={quote(_OPTS['openalex_key'], safe='')}")
            if _cb_open(url):
                return ""

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 · scripts/verify_refs.py (reported line 560)May include surrounding context.

python
if len(cn) >= 12 and (_OPTS.get("openalex_key") or ""):
        try:
            q = quote(claimed.strip(), safe="")
            url = (f"https://api.openalex.org/works?search=%7Bq%7D&per-page=1"
                   f"&select=display_name&api_key={quote(_OPTS['openalex_key'], safe='')}")
            if _cb_open(url):
                return ""

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 · mcp/verify_refs.py (reported line 643)May include surrounding context.

python
# v3.6 --cn 回源:api.crossref.org/works/{doi} 返回同构 CSL(message 字段)。
        # 独立主机不计入 doi.org 断路器;失败静默回原路径。
        try:
            cr_url = f"https://api.crossref.org/works/{quote(doi, safe='()/')}"
            cr_req = urllib.request.Request(cr_url, headers={
                "User-Agent": ua_contact, "Accept": "application/json"})
            with urllib.request.urlopen(cr_req, timeout=timeout) as resp:

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 · mcp/verify_refs.py (reported line 1940)May include surrounding context.

python
"notice_doi": "", "when": raw_date, "source": "local",
                "check_failed": False}
    mailto = _OPTS.get("mailto") or ""
    url = f"https://api.crossref.org/works/{quote(doi, safe='()/')}"
    if mailto:
        url += f"?mailto={quote(mailto, safe='@')}"
    if _cb_open(url):

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 · mcp/verify_refs.py (reported line 4535)May include surrounding context.

python
_DOCTOR_PROBES = [
    ("DOI.org 解析", "https://doi.org/10.3866/PKU.WHXB201112303"),
    ("Crossref API", "https://api.crossref.org/works?rows=0&mailto=doctor%40cite-holmes"),
    ("PubMed E-utilities", "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/"
                           "esearch.fcgi?db=pubmed&retmode=json&retmax=0&term=cite+holmes+doctor"),
    ("arXiv API", "https://export.arxiv.org/api/query?search_query=all%3Acite&max_results=1"),

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 · scripts/verify_refs.py (reported line 643)May include surrounding context.

python
# v3.6 --cn 回源:api.crossref.org/works/{doi} 返回同构 CSL(message 字段)。
        # 独立主机不计入 doi.org 断路器;失败静默回原路径。
        try:
            cr_url = f"https://api.crossref.org/works/{quote(doi, safe='()/')}"
            cr_req = urllib.request.Request(cr_url, headers={
                "User-Agent": ua_contact, "Accept": "application/json"})
            with urllib.request.urlopen(cr_req, timeout=timeout) as resp:

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 · scripts/verify_refs.py (reported line 1940)May include surrounding context.

python
"notice_doi": "", "when": raw_date, "source": "local",
                "check_failed": False}
    mailto = _OPTS.get("mailto") or ""
    url = f"https://api.crossref.org/works/{quote(doi, safe='()/')}"
    if mailto:
        url += f"?mailto={quote(mailto, safe='@')}"
    if _cb_open(url):

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 · mcp/verify_refs.py (reported line 1086)May include surrounding context.

python
ou = None
    try:
        q = quote(topic, safe="")
        ou = (f"https://api.openalex.org/works?search=%7Bq%7D&per-page=%7Blimit}"
              "&select=display_name,publication_year,doi,primary_location"
              + ("&sort=cited_by_count:desc" if sort == "cited" else
                 "&sort=publication_date:desc" if sort == "newest" else ""))

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 · mcp/verify_refs.py (reported line 4539)May include surrounding context.

python
("PubMed E-utilities", "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/"
                           "esearch.fcgi?db=pubmed&retmode=json&retmax=0&term=cite+holmes+doctor"),
    ("arXiv API", "https://export.arxiv.org/api/query?search_query=all%3Acite&max_results=1"),
    ("OpenAlex", "https://api.openalex.org/works?per-page=1&select=id"),
    ("Semantic Scholar", "https://api.semanticscholar.org/graph/v1/paper/"
                         "DOI:10.3866/PKU.WHXB201112303?fields=title"),
    ("Wayback 存档", "https://archive.org/wayback/available?url=example.com"),

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 · scripts/verify_refs.py (reported line 1086)May include surrounding context.

python
ou = None
    try:
        q = quote(topic, safe="")
        ou = (f"https://api.openalex.org/works?search=%7Bq%7D&per-page=%7Blimit}"
              "&select=display_name,publication_year,doi,primary_location"
              + ("&sort=cited_by_count:desc" if sort == "cited" else
                 "&sort=publication_date:desc" if sort == "newest" else ""))

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 · mcp/verify_refs.py (reported line 1990)May include surrounding context.

python
if len((title or "").strip()) < 18:
        return "", False, ""
    q = quote(title.strip(), safe="")
    url = (f"https://api.openalex.org/works?search=%7Bq%7D&per-page=3"
           "&select=display_name,publication_year,doi")
    key = _OPTS.get("openalex_key") or ""
    if key:

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 · scripts/verify_refs.py (reported line 1990)May include surrounding context.

python
if len((title or "").strip()) < 18:
        return "", False, ""
    q = quote(title.strip(), safe="")
    url = (f"https://api.openalex.org/works?search=%7Bq%7D&per-page=3"
           "&select=display_name,publication_year,doi")
    key = _OPTS.get("openalex_key") or ""
    if key:

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
mcp/verify_refs.py:2072

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/verify_refs.py:2072