Back to skill

Security audit

Aip Identity

Security checks for vulnerabilities and agentic risk

Overview

This identity skill mostly matches its stated purpose, but some security-sensitive features can expose content or credentials in ways users would not reasonably expect.

Review this skill carefully before installing. Use it only if you are comfortable with the AIP service receiving identity metadata and signed content, avoid signing sensitive files, avoid sending sensitive replies until the reply path is encrypted, protect aip_credentials.json with strict local permissions, and pin/audit dependencies before using it in a security-sensitive workspace.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/aip.py:237
Finding

Signing Command Uploads Complete User Content to a Remote Service

Content
View full analysis
`. 2. The script reads the entire selected file into memory. 3. The script calculates a hash and signature locally. 4. It serializes the original content into the `skill_content` JSON field. 5. The complete ...[truncated 631 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/aip.py:443
Finding

Reply Command Sends Message Content Without End-to-End Encryption

Content
View full analysis
""`. 3. The command retrieves the original message to determine its sender. 4. It constructs a plaintext reply in `content`. 5. It signs the plaintext but does not encrypt it. 6. The plaintext is transmitted to the remote service, where it can be read or logged. ### Impact Assessment The AIP service, service operators, server-side logs, and any party obtaining access to those systems may read reply contents. Sensitive agent communications may therefore be exposed despite the user's reasonable expectation of end-to-end encryption. The issue compromises message confidentiality. It does not itself grant ...[truncated 135 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/aip.py:177
Finding

Private Keys Are Written to Plaintext Files Without Enforced Restrictive Permissions

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:31
Finding

Installation Guidance Uses Unpinned Third-Party Dependencies

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/aip.py:44
Finding

Messaging Uses Incompatible and Incorrect Public-Key Encryption Constructions

Content
View full analysis
str: import nacl.public sender_sk = nacl.public.PrivateKey(base64.b64decode(sender_priv_b64)[:32]) recipient_pk = nacl.public.PublicKey(base64.b64decode(recipient_pub_b64)) box = nacl.public.Box(sender_sk, recipient_pk) encrypted = box.encrypt(plaintext) return base64.b64encode(encrypted).decode() ``` The receiver converts the Ed25519 signing key and attempts to decrypt using `SealedBox`: ```python priv_bytes = base64.b64decode(creds["private_key"]) signing_key = nacl.signing.SigningKey(priv_bytes) curve_priv = signing_key.to_curve25519_private_key() sealed_box = nacl.public.SealedBox(curve_priv) plaintext = sealed_box.decrypt(base64.b64decode(content)) print(f" Content: {plaintext.decode()}") ``` ### Technical Analysis Ed25519 signing keys and Curve25519 encryption keys are not interchangeable by simply reinterpreting their raw bytes. PyNaCl provides explicit conversion methods because the correct Curve25519 key is derived through a defined conversion process. The sender constructs `nacl.public.PrivateKey` and `PublicKey` directly from raw Ed25519 bytes, while the receiver correctly converts its signing key with `to_curve25519_private_key()`. The resulting keypairs will not generally correspond. There is also a construction mismatch: encryption uses authenticated `Box`, while decryption uses `SealedBox`. Ciphertexts produced by `Box.encrypt()` are not `SealedBox` ciphertexts and cannot be decrypted through `SealedBox.decrypt()`. This can cause systematic decryption failure and undermines the skill's stated secure-messaging functionalit ...[truncated 1063 chars]
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (20)

Tainted flow: 'req' from os.environ.get (line 106, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
92% confidence
Finding

The base service URL is taken directly from the AIP_SERVICE_URL environment variable and then used for all network requests, including registration, challenge-response authentication, key rotation, and message operations. In an agent environment, a hostile parent process or workspace configuration could redirect the client to an attacker-controlled service, causing exfiltration of DIDs, usernames, signed challenges, encrypted messages, and even private keys in deprecated registration mode.

Content

Scanner excerpt · scripts/aip.py (reported line 109)May include surrounding context.

python
req = urllib.request.Request(url, data=body, method=method,
                                headers={"Content-Type": "application/json"} if body else {})
    try:
        with urllib.request.urlopen(req, timeout=15) as resp:
            return json.loads(resp.read())
    except urllib.error.HTTPError as e:
        err = e.read().decode()

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The documented purpose emphasizes secure identity, signing, and encrypted messaging, but the referenced behavior includes undeclared administrative-style registry access and a reply path that may send plaintext message content. That mismatch is dangerous because users and orchestrators may trust the skill for privacy-sensitive workflows while hidden or under-disclosed behaviors expose metadata, registration data, or message content beyond expected boundaries.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
89% confidence
Finding

The skill explicitly stores a private key in a local JSON credential file and supports path selection via an environment variable, which creates a high-value target for theft or misuse if filesystem permissions, logging, backups, or path handling are weak. In the context of an identity skill, compromise of this file enables impersonation, fraudulent signatures, message decryption, and unauthorized trust actions.

Content

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

md
## Credentials

Stored as JSON in `aip_credentials.json`: `{ "did", "public_key", "private_key", "platform", "username" }`.
**Never share `private_key`.** DID and public_key are safe to share.

Set `AIP_CREDENTIALS_PATH` env var to use a custom credential file location instead of the default search path.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% 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 · references/api.md (reported line 127)May include surrounding context.

md
### PATCH /message/\<id\>/read
Mark message as read (requires signature of message_id).

### DELETE /message/\<id\>
Signs: `{message_id}`

---

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/aip.py (reported line 11)May include surrounding context.

python
from datetime import datetime, timezone

AIP_BASE = os.environ.get("AIP_SERVICE_URL", "https://aip-service.fly.dev")
DEFAULT_CREDS = "aip_credentials.json"

def _find_creds_file(filename=DEFAULT_CREDS):
    """Search for credentials in multiple standard locations."""

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The reply command presents itself as replying to a received message, but instead of reusing the encrypted messaging flow it sends plaintext content to a different endpoint. Users may reasonably assume replies are protected like messages, so this mismatch can leak sensitive content to the service or intermediaries and undermines the security guarantees implied by 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 commands that require shell execution, network access, environment-variable use, and local file writes, but it does not declare any tool scope or permission boundaries. This creates a transparency and governance gap: an agent may invoke a capability-rich skill without explicit authorization controls, increasing the chance of unintended network calls, credential handling, or filesystem modification.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The description says to use the skill whenever an agent needs identity verification, authentication, trust scoring, secure messaging, or reputation management, followed by a very broad coverage list. This is invocation guidance in a manifest context, and it lacks explicit boundaries or negative examples to distinguish when this skill should not be selected, increasing the chance of unintended activation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The reference documents destructive and sensitive operations such as message deletion, key rotation, revocation, and admin registration access without warning users that these actions are security-sensitive and potentially irreversible. In a skill meant for autonomous agents handling identity and trust, omission of guardrails increases the chance that an agent or operator invokes high-impact endpoints unsafely or with incomplete authorization assumptions.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The API reference exposes admin-only registration listing and detail endpoints in general documentation without any stated authorization requirements or justification tied to the skill’s end-user identity/trust workflow. In an agent ecosystem, documenting enumeration-capable admin surfaces can encourage misuse, probing, and bulk collection of identity metadata even if the backend is intended to enforce auth.

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/aip.py (reported line 60)May include surrounding context.

python
with tempfile.NamedTemporaryFile(suffix=".pem", delete=False) as f:
        kf = f.name
    try:
        subprocess.run(["openssl", "genpkey", "-algorithm", "Ed25519", "-out", kf],
                       check=True, capture_output=True)
        raw = subprocess.run(["openssl", "pkey", "-in", kf, "-outform", "DER"],
                             check=True, capture_output=True).stdout

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/aip.py (reported line 62)May include surrounding context.

python
try:
        subprocess.run(["openssl", "genpkey", "-algorithm", "Ed25519", "-out", kf],
                       check=True, capture_output=True)
        raw = subprocess.run(["openssl", "pkey", "-in", kf, "-outform", "DER"],
                             check=True, capture_output=True).stdout
        seed = raw[-32:]
        pub_raw = subprocess.run(

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/aip.py (reported line 65)May include surrounding context.

python
raw = subprocess.run(["openssl", "pkey", "-in", kf, "-outform", "DER"],
                             check=True, capture_output=True).stdout
        seed = raw[-32:]
        pub_raw = subprocess.run(
            ["openssl", "pkey", "-in", kf, "-pubout", "-outform", "DER"],
            check=True, capture_output=True).stdout
        pub = pub_raw[-32:]

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/aip.py (reported line 92)May include surrounding context.

python
with tempfile.NamedTemporaryFile(suffix=".dat", delete=False) as f:
            f.write(message)
            df = f.name
        result = subprocess.run(
            ["openssl", "pkeyutl", "-sign", "-inkey", kf, "-rawin", "-in", df],
            check=True, capture_output=True)
        return base64.b64encode(result.stdout).decode()

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The registration flow writes a credentials file containing the private key to disk in plaintext. Although the script later mentions backup, it does not provide a meaningful pre-write consent prompt, secure-storage choice, or permission hardening, which is risky in shared agent workspaces where other tools or users may access the file.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Key rotation silently overwrites the credentials file with new private key material, again storing secrets on disk without an explicit warning or secure-storage handling. This can surprise users, disrupt backup expectations, and expose fresh credentials if the file location is accessible to other processes.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The list command exposes bulk registry enumeration through an admin-style endpoint, which exceeds the stated purpose of point identity verification and secure messaging. This enables large-scale discovery of registered identities and associated platform usernames, increasing privacy and reconnaissance risk.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Calling /admin/registrations directly from a general-purpose client enables bulk discovery of all registered agents, which is not required for ordinary identity operations. In context, this increases privacy exposure and makes targeted abuse or scraping easier.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The trust-graph command performs registry-wide enumeration and then queries vouches for each discovered agent to build a global social graph. That creates unnecessary reconnaissance capability and can expose relationship metadata well beyond normal identity verification needs.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The code chains administrative registration listing with per-agent vouch retrieval to perform registry-wide trust reconnaissance. For an identity tool, this broad collection of network relationship data is excessive and raises privacy and targeting concerns.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.