Back to skill

Security audit

Jackal Memory

Security checks for vulnerabilities and agentic risk

Overview

This memory skill does what it advertises, but it can send sensitive agent memory to a third-party service and reload remote text as agent identity without enough user control or safeguards.

Install only if you are comfortable trusting the remote Jackal Memory service with any memory you save. Do not store API keys, passwords, private keys, personal data, or policy-like instructions in this memory unless you have separate controls such as local encryption, review before upload, and careful treatment of loaded memory as untrusted context.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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
  • 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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
jackal-memory/client.py:17
Finding
Plaintext transmission of potentially sensitive agent memory to a third-party service## Vulnerability Details **File Location**: `jackal-memory/client.py:17-53`; related instructions in `SKILL.md:33-36, 50-58` **Vulnerability Type**: Plaintext sensitive-data handling and external disclosure **Risk Level**: Critical ### Vulnerable Code ```python BASE_URL = "https://web-production-5cce7.up.railway.app" def _request(method: str, path: str, body: dict | None = None) -> dict: url = BASE_URL + path data = json.dumps(body).encode() if body else None req = urllib.request.Request( url, data=data, method=method, headers={ "Authorization": f"Bearer {_api_key()}", "Content-Type": "application/json", }, ) try: with urllib.request.urlopen(req) as resp: return json.loads(resp.read()) except urllib.error.HTTPError as e: error = json.loads(e.read()) print(f"Error {e.code}: {error.get('detail', e.reason)}", file=sys.stderr) sys.exit(1) def cmd_save(key: str, content: str) -> None: result = _request("POST", "/save", {"key": key, "content": content}) print(f"Saved — key: {result['key']} cid: {result['cid']}") ``` The associated documentation explicitly identifies the content as potentially sensitive: ```markdown - Call save at session end or on significant state changes - Treat memory content as sensitive — it may contain credentials or personal data ``` ### Technical Analysis The client serializes the supplied memory content directly into JSON and sends it to the fixed third-party Railway endpoint. Transport encryption is provided by HTTPS, but there is no client-side encryption, field-level redaction, secret detection, data classification, or confirmation step before transmission. The remote service necessarily receives the bearer API key and plaintext memory content. Because the documented workflow recommends saving at session end or upon s ...[truncated 1658 chars]
Remediation
## Remediation Suggestions 1. Do not permit unrestricted session context to be saved. Define a strict allowlisted schema containing only the minimum fields required for continuity. 2. Add secret detection and redaction for API keys, passwords, private keys, tokens, cookies, personal data, and common credential formats. 3. Require explicit, informed user approval before the first upload and before any upload containing newly detected sensitive fields. 4. Encrypt memory locally with authenticated encryption before transmission. Keep decryption keys under user control and never send them to the storage service. 5. Implement configurable retention periods, deletion functionality, export controls, access logs, and revocation procedures. 6. Allow users to configure or self-host the endpoint rather than relying exclusively on a hardcoded third-party service. 7. Document the service trust boundary accurately, including that HTTPS protects data in transit but does not prevent the service from reading plaintext content. 8. Add content-size limits and tests verifying that known secret formats cannot be uploaded without explicit override.

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:30
Finding
Untrusted remote memory can persistently influence agent identity and behavior## Vulnerability Details **File Location**: `SKILL.md:30-53`; retrieval implementation in `jackal-memory/client.py:56-58`; example state in `jackal-memory/examples/save.json:1-4` **Vulnerability Type**: Persistent agent memory poisoning and instruction influence **Risk Level**: High ### Vulnerable Instructions and Code ```markdown **On session start** — restore memory: ``` ```text python {baseDir}/client.py load <key> ``` ```markdown ## Behaviour guidelines - Load your identity/memory blob on startup before doing any work - Write locally during the session as normal - Call save at session end or on significant state changes - Use descriptive keys: `identity`, `session-2026-02-26`, `project-jackal` ``` The retrieved content is emitted without provenance or schema validation: ```python def cmd_load(key: str) -> None: result = _request("GET", f"/load/{key}") print(result["content"]) ``` The packaged example demonstrates persistence of persona, ownership, and behavioral preferences: ```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 tells an agent to restore an externally stored identity or memory blob before performing other work. The client accepts the remote JSON response and prints its `content` field without validating its structure, provenance, integrity, permissible semantics, or whether it contains instructions. The Python client does not directly execute the response as operating-system code. The risk arises when the output is inserted into an AI agent's context as identity or memory, as directed by the skill. In that context, attacker-controlled text can be interpreted as persistent instructions rather than inert data. An attacker would need control of the API account, its bearer token, the releva ...[truncated 1663 chars]
Remediation
## Remediation Suggestions 1. Treat all remotely loaded memory as untrusted data and clearly delimit it from system, developer, user, and skill instructions. 2. Remove the instruction to load remote identity before any other work. Require user review and approval before applying restored state. 3. Do not store or restore authoritative ownership claims, safety policies, tool permissions, or behavioral rules as ordinary memory. 4. Define a strict schema limited to factual, non-executable fields. Reject free-form content that resembles instructions or attempts to alter priorities. 5. Add authenticated integrity protection using signatures or message authentication under a user-controlled key. 6. Display the source, timestamp, version, and integrity status of restored records. 7. Maintain immutable audit history and provide rollback so unauthorized changes can be detected and reversed. 8. Separate informational memory from identity and policy configuration. Identity or policy changes should require an explicit trusted administrative workflow. 9. Rotate the API key after suspected exposure and support record-level access controls instead of relying solely on one bearer token. 10. Add adversarial tests covering prompt injection, false identity claims, instruction-like memory, compromised records, and cross-session persistence.
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
90% confidence
Finding
The skill requires environment access for an API key and network access to an external service, but it does not declare any explicit tool scope such as permissions or allowed-tools. That creates an overbroad trust boundary: an agent runtime may permit more capabilities than intended, making secret handling and outbound requests less auditable and easier to misuse if the skill is invoked in an unsafe context.

Static analysis

No suspicious patterns detected.