Back to skill

Security audit

Agent SCIF

Security checks for vulnerabilities and agentic risk

Overview

This vault skill is not proven malicious, but it needs Review because it manages secrets through a sub-agent and Telegram while leaving serious injection, file-scope, temporary-file, and key-persistence risks.

Treat this as a proof-of-concept, not a production secrets manager. Only use it in an isolated environment with low-value test secrets unless the author first fixes destination validation, sender_id path constraints, temporary-file handling, model-generated code execution, session-key storage, and dependency pinning.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (7)

T01 · Skill Instruction Hijacking

Error
Location
scripts/vault_cleanroom.py:59
Finding

Unvalidated Telegram Chat ID Enables Clean-Room Prompt Injection

Content
View full analysis
str: _validate_inputs(sender_id, totp_code) """ Returns the task prompt for the vault sub-agent. """ ``` The unvalidated value is subsequently embedded directly into the generated task: ```python return f"""You are the TARS Vault clean-room agent. Your job: manage an open vault session with total isolation from the main TARS session. SETUP (do this first): 1. Run this command to open the vault: {venv_py} {vault_py} open {sender_id} {totp_code} 2. Send the output DIRECTLY to the user's Telegram chat ID: {telegram_chat_id} Use the message tool: action=send, channel=telegram, target={telegram_chat_id} ``` ### Technical Analysis The function validates `sender_id` and `totp_code`, but it does not validate or encode `telegram_chat_id`. That value is interpolated multiple times into a natural-language task that is intended to be passed to `sessions_spawn`. Because the destination is represented as prompt text rather than trusted structured metadata, a value containing line breaks and additional instructions can alter the spawned agent's goals. The clean-room agent has access to decrypted vault entries and a messaging tool, making this an instruction-boundary violation with direct confidentiality consequences. This behavior exceeds minimu ...[truncated 1235 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/vault_cleanroom.py:83
Finding

Attacker-Controlled Vault Content Is Converted into Executable Python Source

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/vault_cleanroom.py:86
Finding

Predictable Shared Temporary File Permits Symlink and Race Attacks

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/vault.py:94
Finding

Insufficient Sender-ID Sanitization Enables Vault Path Traversal

Content
View full analysis
str: return sender_id.replace('+', '').replace(':', '_') def paths(sender_id: str): sid = sid_clean(sender_id) return { 'totp': VAULT_DIR / f'{sid}.totp', 'meta': VAULT_DIR / f'{sid}.meta', 'vault': VAULT_DIR / f'{sid}.vault', } ``` The unrestricted value is accepted by the core command-line interface: ```python s = sub.add_parser('setup'); s.add_argument('sender_id'); s.add_argument('--name', default='') o = sub.add_parser('open'); o.add_argument('sender_id'); o.add_argument('code') a = sub.add_parser('add'); a.add_argument('sender_id'); a.add_argument('content', nargs='+'); a.add_argument('--code', default=None) cl = sub.add_parser('close'); cl.add_argument('sender_id') d = sub.add_parser('delete'); d.add_argument('sender_id'); d.add_argument('index', type=int); d.add_argument('--code', default=None) st = sub.add_parser('status'); st.add_argument('sender_id') ``` ### Technical Analysis `sid_clean()` removes only plus signs and replaces colons. It does not reject directory separators, `..` components, absolute paths, control characters, or platform-specific path syntax. Although `vault_cleanroom.py` applies a regular expression to sender IDs in one workflow, `vault.py` is independently executable and performs no equivalent validation. Security validation at one caller therefore does not protect the core file-access boundary. ### Attack Path 1. An attacker invokes `vault.py` directly with a traversal-containing sender ID. 2. `sid_clean()` leaves traversal components intact. 3. `paths()` combines the resulting value with `VAULT_DIR`. 4. Filesystem resolution reaches a location outside the intended vault directory. 5. Commands such as `setup`, `open`, or `status` create, ov ...[truncated 602 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/vault.py:161
Finding

Base64-Encoded Vault Key Persists Beyond the Claimed Session Expiry

Content
View full analysis
bytes | None: sp = session_path(sender_id) if not sp.exists(): return None try: data = json.loads(sp.read_text()) except Exception: sp.unlink() return None if time.time() > data['expires']: sp.unlink() return None return base64.b64decode(data['vault_key']) def session_end(sender_id: str): sp = session_path(sender_id) if sp.exists(): sp.unlink() ``` ### Technical Analysis Base64 is an encoding mechanism, not encryption. Anyone able to read `session.json` can immediately reconstruct the raw vault key. The `expires` value does not trigger deletion by itself. Expired data is removed only when `session_load()` is subsequently called, or when `session_end()` is explicitly invoked. If the process crashes, the clean-room session is abandoned, or no later load occurs, the key remains recoverable from disk beyond the advertised two-hour lifetime. The flagged Base64 operation is not itself a stdout or network exfiltration channel: `session_start()` writes it to a local file through `secure_write()`. The confirmed risk is plaintext-equivalent key persistence, not covert output. ### Attack Path 1. A user successfully opens a vault. 2. `session_start()` serializes the raw vault key into `/tmp/.vault-/session.json`. 3. The clean-room workflow crashes or terminates without invoking `session_end()`. 4. No subsequent call to `session_load()` occurs to enforce the timestamp. 5. ...[truncated 578 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/vault.py:233
Finding

TOTP Enrollment QR Code Is Persisted Without Explicit Restrictive Permissions

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:95
Finding

Security-Critical Python Dependencies Are Installed Without Version or Hash Pinning

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

The skill description focuses on encrypted secret storage, but the documented behavior also includes direct outbound messaging, persistent /tmp session tracking, and orchestration of a separate sub-agent. This mismatch is dangerous because operators may approve or trust the skill as a simple vault when it also has messaging and session-management capabilities that expand the attack surface and data-flow exposure.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The skill description focuses on encrypted secret storage, but the documented behavior also includes direct outbound messaging, persistent /tmp session tracking, and orchestration of a separate sub-agent. This mismatch is dangerous because operators may approve or trust the skill as a simple vault when it also has messaging and session-management capabilities that expand the attack surface and data-flow exposure.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill advertises that the agent 'holds but cannot read' secrets, yet the open command decrypts the vault and prints every entry's plaintext to stdout. This directly defeats the stated trustless model: any caller, wrapper process, logs, or terminal capture can access the decrypted secrets once a valid TOTP is supplied.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The implementation contradicts the skill description by instructing a sub-agent to open the vault and send decrypted contents externally. Even if the main orchestration agent does not itself parse the secrets, the overall system absolutely can read and disclose them, which is a security-boundary violation and can mislead users into overtrusting the skill.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The 'blind relay' and 'never decrypts vault' language describes a stronger isolation model than the code actually enforces. Security-sensitive misrepresentation is dangerous because operators and users may make trust decisions based on a false assumption that no agent session can access vault contents, when the generated task explicitly enables such access.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · scripts/vault_cleanroom.py (reported line 95)May include surrounding context.

python
Step 2: Pipe into vault:
      cat /tmp/.vault_input | {venv_py} {vault_py} add {sender_id} -
    Step 3: Clean up:
      rm /tmp/.vault_input
    Send result directly to Telegram {telegram_chat_id}

- "delete from vault: [index]" →

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The invocation phrase "add to vault: [content]" is broad and accepts arbitrary free-form content with no scoping constraints, confirmation step, or exclusion examples. In a chat-driven agent environment, this increases the chance of accidental triggering, prompt-collision with normal conversation, or unintended routing of sensitive content into the vault workflow when the user did not explicitly mean to invoke the skill.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill invokes shell commands and performs file reads/writes, but it declares no tool scope or allowed-tools restrictions. That increases the blast radius because a host agent may grant broader capabilities than necessary, making misuse or prompt-injection-driven command execution more likely.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

text
scripts/vault.py           — core crypto + vault operations
scripts/vault_cleanroom.py — clean room orchestration
vault/<sender_id>.totp     — TOTP seed (chmod 600, never log)
vault/<sender_id>.meta     — encrypted vault key + KDF params
vault/<sender_id>.vault    — encrypted entries
/tmp/.vault-<sid>/         — session dir (mode 0o700, auto-cleaned)

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module header presents a 'trustless' design and claims TARS never sees plaintext when locked, but the operational flow stores the TOTP seed locally, derives the vault key, decrypts entries, and exposes plaintext after unlock. This is dangerous because it can mislead users into entrusting highly sensitive data under a stronger security model than the code actually enforces.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/vault.py (reported line 19)May include surrounding context.

python
[MEDIUM]   PBKDF2 -> Argon2id (GPU/ASIC resistant)
  [MEDIUM]   AAD = sender_id bound to all AES-GCM operations
  [MEDIUM]   Entry size limit (1MB per entry)
  [MEDIUM]   Explicit chmod 600 on all sensitive files

Usage:
  vault.py setup <sender_id> [--name <label>]

Session Persistence

Medium
Category
Rogue Agent
Confidence
88% confidence
Finding

The skill persists sensitive material to disk, including the TOTP seed in the vault directory and the decrypted vault key in /tmp-based session files for up to two hours. Even with 0600 permissions, disk-backed persistence expands the attack surface to local compromise, backups, forensic recovery, symlink/path attacks in shared environments, and secret theft by any process running as the same user.

Content

Scanner excerpt · scripts/vault.py (reported line 98)May include surrounding context.

python
}

def secure_write(path: Path, text: str):
    """Write file and enforce 600 permissions."""
    path.write_text(text)
    path.chmod(0o600)

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code explicitly directs a sub-agent to transmit vault output to Telegram, creating an outbound exfiltration path for decrypted secrets. In a skill advertised as secure secret storage where the main agent supposedly cannot read secrets, adding direct messaging materially increases the chance of unauthorized disclosure through the messaging tool, chat misbinding, or prompt misuse.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

A session key is persisted to disk under /tmp, which expands the exposure window if the host is shared, compromised, or subject to forensic recovery. Although file permissions are restricted, storing active session metadata on disk without stronger lifecycle controls can enable session hijacking or unauthorized command relay into the vault sub-agent.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Hard-coding Telegram as the output channel forces decrypted vault responses onto an external messaging platform regardless of user choice or sensitivity. In the context of secret management, this broadens the attack surface and makes misdelivery, account compromise, chat-ID confusion, or unintended retention in third-party infrastructure much more consequential.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
74% confidence
Finding

The instructed workflow writes vault entry content to a fixed temporary file in /tmp, causing sensitive plaintext to persist on disk during processing and potentially after failures. In a secret-storage skill, temporary plaintext persistence undermines the clean-room model and may expose secrets through races, crash residue, or local host inspection.

Content

Scanner excerpt · scripts/vault_cleanroom.py (reported line 85)May include surrounding context.

python
After setup, you will receive commands via this session (forwarded from main TARS). For each command:

- "add to vault: [content]" →
    Write content safely via Python (avoids all shell quoting/injection issues):
    Step 1: Write to temp file using exec tool with a Python script:
      import tempfile, os
      content = [content as a Python string literal]

Vague Triggers

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The phrase "close vault" is short, generic, and likely to appear in ordinary discussion, making accidental invocation plausible. While the direct security impact is lower than unauthorized opening or writing, unintended closure could disrupt workflows, terminate the clean-room session unexpectedly, and create availability or integrity issues around an active secure interaction.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.