Back to skill

Security audit

arxivkb

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its arXiv paper-search purpose, but installation creates persistent background scheduling and broad environment changes without enough clear opt-in control.

Review install.py before installing. Prefer running it in a dedicated virtual environment, remove or disable the systemd/launchd scheduling steps unless you explicitly want daily background ingestion, and avoid using the expire -y option unless you intend permanent deletion of the skill's stored papers and PDFs.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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
Findings (4)

T06 · System Persistence

Error
Location
scripts/install.py:117
Finding

Installer Automatically Enables a Persistent Scheduled Task

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/install.py:33
Finding

Installer Retrieves Unpinned Dependencies and Upgrades Shared User Packages

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/arxiv_crawler.py:123
Finding

Remote PDF Downloads Lack URL Validation and Response Size Limits

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/db.py:265
Finding

Public Database Helper Interpolates an Unvalidated ORDER BY Expression

Content
View full analysis
list[dict]: conn = open_db(db_path) try: where = "WHERE status = ?" if status else "" params: list[Any] = [status] if status else [] params.append(limit) rows = conn.execute(f"SELECT * FROM papers {where} ORDER BY {order_by} LIMIT ?", params).fetchall() return _rows_to_dicts(rows) finally: conn.close() ``` ### Technical Analysis The `status` and `limit` values are parameterized correctly, but `order_by` is inserted directly into the SQL statement through an f-string. SQL placeholders cannot ordinarily represent identifiers or sort directions, so those elements must be selected from a strict allowlist. As written, a caller can supply arbitrary SQLite ordering expressions and alter the structure of the query. No current in-project caller was found that passes user-controlled data into `order_by`, so the issue is presently a latent injection sink rather than a confirmed remotely reachable injection endpoint. It can become exploitable if the helper is exposed through the companion dashboard, a future API, or a CLI sorting option. SQLite's Python interface generally restricts `execute()` to one statement, reducing the likelihood of straightforward stacked-statement attacks, but it does not make arbitrary injected SQL expressions safe. ### Attack Path 1. A future or external caller accepts a sort expression from an untrusted user. 2. The caller forwards that value to `list_papers(order_by=...)`. 3. The value is interpolated after `ORDER BY` without validation. 4. SQLite evaluates the attacker-controlled SQL expression as part of the query. 5. The attacker may manipulate ordering, invoke expensive expressions, ...[truncated 581 chars]
Remediation
View remediation
list[dict]: column = _ALLOWED_SORT_FIELDS.get(sort_field) if column is None: raise ValueError("Unsupported sort field") direction = "DESC" if descending else "ASC" conn = open_db(db_path) try: where = "WHERE status = ?" if status else "" params = [status] if status else [] params.append(limit) rows = conn.execute( f"SELECT * FROM papers {where} ORDER BY {column} {direction} LIMIT ?", params, ).fetchall() return _rows_to_dicts(rows) finally: conn.close() ``` Additional hardening should include: 1. Enforcing a reasonable upper bound on `limit`. 2. Keeping SQLite extension loading disabled. 3. Adding tests that reject SQL fragments, comments, function calls, and unsupported sort fields. 4. Ensuring future API or dashboard layers never forward raw sort strings to database helpers. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (27)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README states that installation will schedule a daily ingest cron/system service, which is a persistent system behavior change. Even though it is disclosed later in the install effects list, there is no explicit warning, opt-in prompt, or emphasis that the installer modifies background task scheduling, which can surprise users and expand the operational footprint of the skill.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill advertises and documents capabilities that can access the network, write files, use environment variables, and invoke shell commands, but it does not declare any explicit tool scope or permissions boundary. In an agent environment, this increases the risk of over-privileged execution because the agent may run installation, ingestion, download, and deletion workflows without a clearly constrained allowlist.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill highlights automatic cleanup that deletes old papers, PDFs, and chunks, but the user-facing description does not clearly warn about irreversible local data loss. In a local knowledge-base skill, deletion is expected functionality, yet presenting it without an explicit warning can cause unintended destruction of indexed content a user expected to retain.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
87% confidence
Finding

The documented -y flag allows deletion commands to bypass confirmation, enabling unattended destructive actions. In an agent-integrated skill that can be triggered through chat commands and CLI automation, this increases the chance of accidental or policy-bypassing data deletion, especially if an agent chains commands without sufficient user review.

Content

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

bash
akb expire               # Delete papers older than 90 days (default)
akb expire --days 30     # Override: delete papers older than 30 days
akb expire --days 30 -y  # Skip confirmation

Configuration

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% 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 · scripts/cli.py (reported line 396)May include surrounding context.

python
# expire
    exp = sub.add_parser("expire", help="Delete old papers")
    exp.add_argument("--days", type=int, help="Delete papers older than N days")
    exp.add_argument("--yes", "-y", action="store_true", help="Skip confirmation")

    return parser

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The function deletes a paper record from the database and commits the change immediately, but there is no confirmation prompt, warning message, or explanatory comment indicating that this is a destructive operation. Because this removal is irreversible at the application level and may cascade to related records via the schema, users are not clearly informed of the data-loss impact.

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

python
def run(cmd, check=True):
    print(f"  → {' '.join(cmd)}")
    return subprocess.run(cmd, check=check, capture_output=True, text=True)


def pip_install(packages):

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The installer performs external software acquisition through pip and Ollama, which changes the local environment beyond simple file setup. This increases supply-chain and environment-modification risk, especially because it upgrades packages and pulls models automatically during install.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.py (reported line 49)May include surrounding context.

python
def setup_db(data_dir: Path):
    """Create SQLite DB with tables and seed default categories."""
    db_path = data_dir / "arxivkb.db"
    conn = sqlite3.connect(str(db_path))

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The installer creates persistent scheduled execution via systemd user services and timers, causing the software to continue running automatically after installation. Even if intended for daily ingestion, persistence broadens host impact and creates a standing execution path that could later run modified code or process hostile content without fresh user consent.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.py (reported line 150)May include surrounding context.

python
print("  Start now: systemctl --user start akb-crawler.service")


def setup_launchd_plist(script_dir: Path, python_exe: str, data_dir: Path):
    """Create launchd plist for daily crawl (macOS only)."""
    plist_dir = Path("~/Library/LaunchAgents").expanduser()
    plist_dir.mkdir(parents=True, exist_ok=True)

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.py (reported line 151)May include surrounding context.

python
print("  Start now: systemctl --user start akb-crawler.service")


def setup_launchd_plist(script_dir: Path, python_exe: str, data_dir: Path):
    """Create launchd plist for daily crawl (macOS only)."""
    plist_dir = Path("~/Library/LaunchAgents").expanduser()
    plist_dir.mkdir(parents=True, exist_ok=True)

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.py (reported line 152)May include surrounding context.

python
print("  Start now: systemctl --user start akb-crawler.service")


def setup_launchd_plist(script_dir: Path, python_exe: str, data_dir: Path):
    """Create launchd plist for daily crawl (macOS only)."""
    plist_dir = Path("~/Library/LaunchAgents").expanduser()
    plist_dir.mkdir(parents=True, exist_ok=True)

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.py (reported line 153)May include surrounding context.

python
print("  Start now: systemctl --user start akb-crawler.service")


def setup_launchd_plist(script_dir: Path, python_exe: str, data_dir: Path):
    """Create launchd plist for daily crawl (macOS only)."""
    plist_dir = Path("~/Library/LaunchAgents").expanduser()
    plist_dir.mkdir(parents=True, exist_ok=True)

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.py (reported line 159)May include surrounding context.

python
print("  Start now: systemctl --user start akb-crawler.service")


def setup_launchd_plist(script_dir: Path, python_exe: str, data_dir: Path):
    """Create launchd plist for daily crawl (macOS only)."""
    plist_dir = Path("~/Library/LaunchAgents").expanduser()
    plist_dir.mkdir(parents=True, exist_ok=True)

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.py (reported line 160)May include surrounding context.

python
print("  Start now: systemctl --user start akb-crawler.service")


def setup_launchd_plist(script_dir: Path, python_exe: str, data_dir: Path):
    """Create launchd plist for daily crawl (macOS only)."""
    plist_dir = Path("~/Library/LaunchAgents").expanduser()
    plist_dir.mkdir(parents=True, exist_ok=True)

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.py (reported line 161)May include surrounding context.

python
print("  Start now: systemctl --user start akb-crawler.service")


def setup_launchd_plist(script_dir: Path, python_exe: str, data_dir: Path):
    """Create launchd plist for daily crawl (macOS only)."""
    plist_dir = Path("~/Library/LaunchAgents").expanduser()
    plist_dir.mkdir(parents=True, exist_ok=True)

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.py (reported line 180)May include surrounding context.

python
print("  Start now: systemctl --user start akb-crawler.service")


def setup_launchd_plist(script_dir: Path, python_exe: str, data_dir: Path):
    """Create launchd plist for daily crawl (macOS only)."""
    plist_dir = Path("~/Library/LaunchAgents").expanduser()
    plist_dir.mkdir(parents=True, exist_ok=True)

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.py (reported line 181)May include surrounding context.

python
print("  Start now: systemctl --user start akb-crawler.service")


def setup_launchd_plist(script_dir: Path, python_exe: str, data_dir: Path):
    """Create launchd plist for daily crawl (macOS only)."""
    plist_dir = Path("~/Library/LaunchAgents").expanduser()
    plist_dir.mkdir(parents=True, exist_ok=True)

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.py (reported line 182)May include surrounding context.

python
print("  Start now: systemctl --user start akb-crawler.service")


def setup_launchd_plist(script_dir: Path, python_exe: str, data_dir: Path):
    """Create launchd plist for daily crawl (macOS only)."""
    plist_dir = Path("~/Library/LaunchAgents").expanduser()
    plist_dir.mkdir(parents=True, exist_ok=True)

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.py (reported line 183)May include surrounding context.

python
print("  Start now: systemctl --user start akb-crawler.service")


def setup_launchd_plist(script_dir: Path, python_exe: str, data_dir: Path):
    """Create launchd plist for daily crawl (macOS only)."""
    plist_dir = Path("~/Library/LaunchAgents").expanduser()
    plist_dir.mkdir(parents=True, exist_ok=True)

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.py (reported line 160)May include surrounding context.

python
log_path = Path("~/Library/Logs/akb-crawler.log").expanduser()

    plist = f"""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key><string>com.arxivkb.crawler</string>

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.py (reported line 183)May include surrounding context.

python
</plist>"""
    plist_path = plist_dir / "com.arxivkb.crawler.plist"
    plist_path.write_text(plist)
    print(f"  📝 Plist: {plist_path}")
    print("  Load: launchctl load ~/Library/LaunchAgents/com.arxivkb.crawler.plist")

Session Persistence

Medium
Category
Rogue Agent
Confidence
83% confidence
Finding

The installer instructs the user to load a LaunchAgent that will persistently execute the application on a schedule. In a local paper manager, this is broader than core one-time setup and increases risk because future changes to the referenced script or config could be executed automatically in the user context.

Content

Scanner excerpt · scripts/install.py (reported line 184)May include surrounding context.

python
plist_path = plist_dir / "com.arxivkb.crawler.plist"
    plist_path.write_text(plist)
    print(f"  📝 Plist: {plist_path}")
    print("  Load: launchctl load ~/Library/LaunchAgents/com.arxivkb.crawler.plist")


def main():

Session Persistence

Medium
Category
Rogue Agent
Confidence
83% confidence
Finding

The installer instructs the user to load a LaunchAgent that will persistently execute the application on a schedule. In a local paper manager, this is broader than core one-time setup and increases risk because future changes to the referenced script or config could be executed automatically in the user context.

Content

Scanner excerpt · scripts/install.py (reported line 184)May include surrounding context.

python
plist_path = plist_dir / "com.arxivkb.crawler.plist"
    plist_path.write_text(plist)
    print(f"  📝 Plist: {plist_path}")
    print("  Load: launchctl load ~/Library/LaunchAgents/com.arxivkb.crawler.plist")


def main():

Static analysis

No suspicious patterns detected.