Back to skill

Security audit

Jackal Skill

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent encrypted memory client, but it asks agents to automatically restore and persist sensitive cross-session memory with weak scoping and trust-boundary controls.

Review this before installing if you plan to let an agent auto-load memory. Use a dedicated API key, avoid storing credentials or prompt-like behavioral rules in memory blobs, keep the encryption key private, and consider running it in an environment where file and network access are limited to the documented key path and service endpoint.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T02 · Agent Memory Poisoning

Error
Location
jackal-memory/client.py:128
Finding
Persistent Memory Is Restored Without an Explicit Trust Boundary<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:61-64`, `jackal-memory/client.py:128-130`, and `jackal-memory/examples/save.json:1-4` **Vulnerability Type**: Persistent memory poisoning **Risk Level**: High ### Complete Code Snippets `SKILL.md:61-64`: ```markdown ## Behaviour guidelines - Load your identity/memory blob on startup before doing any work - Write locally during the session as normal ``` `jackal-memory/client.py:128-130`: ```python def cmd_load(key: str) -> None: result = _request("GET", f"/load/{key}") print(_decrypt(result["content"])) ``` `jackal-memory/examples/save.json:1-4`: ```json { "key": "identity", "content": "I am SquireMoltsworth. My owner is FreeNationWW. My primary submolt is m/continuity. I prefer question-based posts over technical specs." } ``` ### Technical Analysis The Skill recommends loading an identity or memory blob before the agent performs other work. The implementation decrypts the remotely stored content and emits it verbatim. It does not impose a schema, distinguish factual memory from behavioral instructions, filter instruction-like content, or require confirmation before identity-related state is restored. AES-GCM protects confidentiality and integrity against parties that do not possess the encryption key. It does not establish that the plaintext originally saved by an authorized session is trustworthy. An authorized but compromised session, a process with access to the encryption key and API credentials, or an agent that saves attacker-controlled text can persist malicious instructions for later sessions. The example explicitly demonstrates that identity and behavioral preferences may be stored in this channel, increasing the likelihood that restored text will be treated as authoritative agent state rather than inert user data. ### Attack Path 1. An attacker supplies instruction-like content to an agent session through an otherwise untrusted input. 2. The authorized agent inco ...[truncated 1123 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Treat all restored memory as untrusted quoted data, not as system-level or developer-level instructions. - Store memory in a strict, versioned schema that separates factual records, user preferences, provenance, and behavioral rules. - Reject or quarantine instruction-like fields that attempt to redefine identity, permissions, safety constraints, or tool-use policy. - Require explicit user confirmation before restoring identity, goals, credentials, or behavioral directives. - Record provenance for each memory entry, including the creating session and whether the content originated from an untrusted source. - Ensure the surrounding agent framework inserts restored data into a non-privileged context and clearly delimits it from executable instructions. - Consider allowlisted keys and field-level validation rather than accepting arbitrary opaque text blobs. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
jackal-memory/client.py:43
Finding
Encryption Key File Is Created Without Explicitly Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `jackal-memory/client.py:43-45` **Vulnerability Type**: Insecure local secret storage **Risk Level**: High ### Complete Code Snippet ```python key_hex = os.urandom(32).hex() _KEY_FILE.parent.mkdir(parents=True, exist_ok=True) _KEY_FILE.write_text(key_hex) ``` ### Technical Analysis The encryption key is written through `Path.write_text()` without explicitly setting a restrictive file mode. The effective permissions therefore depend on the process umask and the state and permissions of the existing parent directory. The directory is also created without an explicit mode. On a multi-user system or in an environment with permissive defaults, another local account or process may be able to read the AES-256 key. The implementation also does not verify file ownership, reject a pre-existing symbolic link, or atomically create the key file with exclusive access. These omissions weaken the local trust boundary protecting all encrypted memory. Knowledge of the encryption key alone permits decryption and creation of valid AES-GCM ciphertext, but remote retrieval or replacement additionally requires access to the stored ciphertext or the memory API. ### Attack Path 1. The client runs for the first time and creates `~/.config/jackal-memory/key` using process-default permissions. 2. A local attacker or process with access under those permissions reads the key file. Alternatively, an unsafe pre-existing filesystem object could redirect the write if the attacker can manipulate the path. 3. The attacker obtains encrypted memory through separate access, such as compromised API credentials, exposed storage responses, or local captured data. 4. The disclosed key is used to decrypt sensitive memory or generate authenticated replacement ciphertext. 5. If the attacker can also write through the API, forged memory can be stored and consumed by future agent sessions. ### Impact Assessment Disclosure of the key compromises t ...[truncated 382 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Create `~/.config/jackal-memory` with mode `0700`. - Create the key file atomically and exclusively with mode `0600`, for example by using `os.open()` with `O_CREAT | O_EXCL | O_WRONLY` and an explicit mode. - Set permissions with `os.chmod()` after creation and verify them before every read. - Verify that the directory and key file are owned by the current user. - Reject symbolic links and non-regular files by using safe open flags where supported and validating with `lstat()` or `fstat()`. - Write the key through an open file descriptor and use an atomic rename strategy where replacement is required. - Prefer an operating-system credential store or hardware-backed key store when available. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:24
Finding
Cryptography Dependency Is Installed Without Version or Integrity Pinning<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:24` **Vulnerability Type**: Unpinned third-party dependency **Risk Level**: Medium ### Complete Code Snippet ```markdown 3. Install dependency: `pip install cryptography` ``` ### Technical Analysis The documented installation command resolves the latest package and transitive dependency versions available from pip's configured package index at installation time. No reviewed version, lockfile, artifact hash, or index restriction is supplied. The package name `cryptography` is legitimate and is not an apparent typosquatting case. The issue is that installation is mutable and not reproducible. If an upstream release, configured package index, package-distribution account, or dependency is compromised, users following the setup instructions may install code that was not part of the audited project. ### Attack Path 1. A user follows the documented `pip install cryptography` command. 2. pip resolves packages from the user's currently configured index without a project-supplied lockfile or required hashes. 3. A compromised or unexpectedly changed package artifact is selected. 4. The package is installed and later imported by `client.py`. 5. Malicious package code can execute with the privileges of the user running the installer or client. This is a supply-chain risk rather than evidence that the currently named upstream package is malicious. ### Impact Assessment A compromised dependency could execute arbitrary code with the invoking user's privileges, access environment variables such as the memory API and encryption keys, read local files available to that user, and modify data accessible by the process. The practical likelihood depends on the security of the configured package source and selected release. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Pin `cryptography` to a reviewed, supported version or narrowly constrained release range. - Supply a lockfile or requirements file containing cryptographic hashes for all resolved artifacts. - Install with hash verification, such as `pip install --require-hashes -r requirements.txt`. - Document the intended authenticated package index and avoid untrusted additional indexes. - Regularly update pins through a controlled dependency-review process that includes vulnerability scanning and compatibility tests. - Install dependencies in an isolated virtual environment with only the privileges required by the client. ]]>
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill requires access to environment secrets, local file read/write, and network communication, but it does not declare any explicit tool scope or permissions boundary. That makes the skill's effective privileges broader and less auditable, increasing the chance that an agent could access sensitive local data or exfiltrate it to the remote service without clear user approval or runtime restriction.

Static analysis

No suspicious patterns detected.