Back to skill

Security audit

A2a E2ee Encryption

Security checks for vulnerabilities and agentic risk

Overview

This skill is not deceptive and does not persist, exfiltrate, or modify local data, but its security-critical cryptographic implementation has correctness gaps users should review before relying on it.

Install only if you understand this is a small crypto utility rather than a reviewed protocol implementation. It does not show malicious behavior, but users should not rely on its secure-envelope or HMAC APIs for high-value agent commands, financial actions, or irreversible workflows without fixing and testing the identified cryptographic edge cases.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
index.js:74
Finding

Incorrect RSA-OAEP plaintext-size calculation causes encryption failures

Content
View full analysis

Vulnerability Details

File Location: index.js:74-92
Vulnerability Type: Incorrect cryptographic boundary validation
Risk Level: Medium

javascript
const maxDirectSize = (RSA_KEY_SIZE / 8) - 42; // PKCS#1 v1.5 padding overhead

if (messageBuffer.length <= maxDirectSize) {
  // Direct RSA encryption for small messages
  const encrypted = crypto.publicEncrypt(
    {
      key: recipientPublicKey,
      padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
      oaepHash: HASH_ALGORITHM
    },
    messageBuffer
  );
  
  return {
    type: 'direct',
    encrypted: encrypted.toString('base64'),
    algorithm: 'RSA-OAEP'
  };
}

Technical Analysis

The implementation calculates the maximum direct RSA plaintext size by subtracting 42 bytes, which is the OAEP overhead associated with SHA-1. However, encryption is configured to use SHA-256.

The RSA-OAEP maximum plaintext size is:

modulusBytes - (2 × hashLength) - 2

For a 2048-bit RSA key and SHA-256, this is 256 - 64 - 2 = 190 bytes. The implementation incorrectly allows up to 214 bytes. Consequently, messages between 191 and 214 bytes are routed to direct RSA encryption and rejected by the underlying cryptographic implementation.

The calculation also relies on the fixed RSA_KEY_SIZE constant rather than inspecting the supplied public key. This produces additional incorrect decisions when callers use keys of a different modulus size.

Attack Path

  1. An attacker supplies or causes the application to encrypt a message between 191 and 214 bytes.
  2. The size check incorrectly selects the direct RSA encryption branch.
  3. crypto.publicEncrypt attempts RSA-OAEP encryption with SHA-256.
  4. OpenSSL rejects the oversized OAEP plaintext and throws an exception.
  5. If the caller does not isolate the exception, the current operation fails and may terminate a request handler or service process.

Impact Assessment

...[truncated 362 chars]

Remediation
View remediation

Remediation Suggestions

  • Derive the modulus length from recipientPublicKey rather than using the fixed RSA_KEY_SIZE constant.
  • Calculate the OAEP boundary using the configured SHA-256 digest length: modulusBytes - (2 * 32) - 2.
  • Prefer hybrid RSA-OAEP and AES-GCM encryption for all message sizes, eliminating the fragile direct-encryption branch.
  • Validate inputs and convert cryptographic exceptions into controlled application errors.
  • Add boundary tests for 189, 190, 191, 213, and 214-byte messages and for every supported RSA key size.

T09 · Insecure Skill Coding Practices

Warning
Location
index.js:217
Finding

Malformed HMAC values can trigger an exception during verification

Content
View full analysis

Vulnerability Details

File Location: index.js:217-220
Vulnerability Type: Improper authentication-input validation
Risk Level: Medium

javascript
function verifyHMAC(message, hmac, key) {
  const computed = computeHMAC(message, key);
  return crypto.timingSafeEqual(Buffer.from(hmac), Buffer.from(computed));
}

Technical Analysis

crypto.timingSafeEqual requires both buffers to have exactly the same byte length. The computed SHA-256 HMAC is represented as a 64-character hexadecimal string, but the untrusted hmac argument is neither decoded as hexadecimal nor validated for its encoding and expected length.

Supplying a string of any different length causes timingSafeEqual to throw a RangeError instead of returning false. The function therefore fails open at the availability boundary: malformed authentication data is handled as an exceptional condition rather than a normal verification failure.

The comparison also operates on UTF-8 representations of hexadecimal strings rather than directly comparing the underlying 32-byte MAC values.

Attack Path

  1. An attacker submits a message with a malformed, truncated, or oversized HMAC value.
  2. verifyHMAC computes the expected 64-character hexadecimal HMAC.
  3. Buffer.from(hmac) and Buffer.from(computed) produce buffers with different lengths.
  4. crypto.timingSafeEqual throws a RangeError.
  5. Without appropriate exception handling, the request fails and may disrupt the enclosing service.

Impact Assessment

An unauthenticated attacker who controls an HMAC input can cause deterministic verification exceptions and application-level denial of service. No privilege escalation, secret disclosure, or authentication bypass was demonstrated. The scope depends on whether the host application catches exceptions around verifyHMAC.

Remediation
View remediation

Remediation Suggestions

  • Require the supplied HMAC to be a valid 64-character hexadecimal value.
  • Decode both values using Buffer.from(value, 'hex') and verify that both decoded buffers are exactly 32 bytes.
  • Return false for invalid encoding or length before invoking timingSafeEqual.
  • Catch unexpected cryptographic errors at the service boundary so malformed authentication data cannot terminate request processing.
  • Add tests for empty, truncated, oversized, non-hexadecimal, and correctly sized invalid HMAC values.

T09 · Insecure Skill Coding Practices

Warning
Location
index.js:283
Finding

Secure envelopes allow replay and do not authenticate timestamp or version metadata

Content
View full analysis

Vulnerability Details

File Location: index.js:283-323
Vulnerability Type: Missing replay protection and incomplete signature coverage
Risk Level: Medium

javascript
function createSecureEnvelope(message, recipientPublicKey, senderPrivateKey) {
  const encrypted = encrypt(message, recipientPublicKey);
  const signature = sign(JSON.stringify(encrypted), senderPrivateKey);
  
  return {
    version: '1.0',
    encrypted,
    signature,
    timestamp: Date.now()
  };
}

function openSecureEnvelope(envelope, recipientPrivateKey, senderPublicKey) {
  // Verify signature
  const signatureValid = verify(
    JSON.stringify(envelope.encrypted),
    envelope.signature,
    senderPublicKey
  );
  
  if (!signatureValid) {
    throw new Error('Invalid signature - message may have been tampered');
  }
  
  // Decrypt message
  const message = decrypt(envelope.encrypted, recipientPrivateKey);
  
  return {
    message,
    signatureValid,
    timestamp: envelope.timestamp
  };
}

Technical Analysis

The signature covers only the serialized encrypted object. Security-relevant envelope metadata, including version and timestamp, is excluded from the signature and can therefore be modified without invalidating it.

In addition, openSecureEnvelope does not enforce a freshness window, validate timestamp semantics, require a unique message identifier, maintain a replay cache, or track sequence numbers. A previously captured valid envelope remains cryptographically valid indefinitely.

Because the returned timestamp is taken directly from the unsigned envelope, an attacker can replace the timestamp on an old message and make it appear current while preserving a valid signature.

Attack Path

  1. An attacker captures a legitimate signed and encrypted envelope in transit or from a message queue or log.
  2. The attacker optionally changes the unsigned timestamp ...[truncated 979 chars]
Remediation
View remediation

Remediation Suggestions

  • Sign a canonical representation of every security-relevant field, including the protocol version, timestamp, ciphertext, sender identity, recipient identity, algorithm identifiers, and a unique message ID or nonce.
  • Avoid relying on ordinary JSON.stringify as a protocol-level canonicalization scheme; use a defined canonical JSON format or a deterministic binary encoding.
  • Enforce a narrowly defined timestamp freshness window and reject timestamps that are too old or unreasonably far in the future.
  • Maintain a replay cache of consumed message IDs for at least the full acceptance window, or use strictly validated per-sender sequence numbers.
  • Bind sender and recipient identities into the signed data to prevent cross-context message reuse.
  • Add tests confirming that metadata modification and duplicate submission are rejected.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The listed trigger scenarios such as 'Need to encrypt messages between agents' and 'Implementing secure communication protocols' are high-level and open-ended, with no explicit constraints or negative examples. This makes the skill's invocation scope ambiguous and increases the chance of unintended activation for general discussions about security or messaging.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The manifest describes key generation, message encryption/decryption, and key management for secure A2A communication. This file additionally exposes generic digital signature and HMAC helpers as first-class APIs, which are broader cryptographic capabilities than the declared encryption-focused scope, even though they are related to secure messaging.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest centers on E2EE for agent-to-agent communication, with key generation and encryption/decryption utilities. The additional shared-secret generation plus symmetric encrypt/decrypt functions introduce a different communication model that is not inherently end-to-end in the asymmetric A2A sense described by the manifest.

Content

No source excerpt is available for this finding.