Back to skill

Security audit

MedCrypt: End-to-End Encryption for Medical Messaging

Security checks for vulnerabilities and agentic risk

Overview

This package appears to be a medical encryption demo, but its security and compliance promises are stronger than what the code actually provides.

Review carefully before installing or using with real patient data. This may be acceptable as a cryptography demo, but it should not be treated as production medical messaging, regulatory compliance tooling, durable audit logging, or reliable emergency recovery without redesign and external review.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
medcrypt.py:95
Finding

Patient Identifier Exposed Through Reversible Base64 Encoding

Content
View full analysis
str: """Encrypt plaintext → MedCrypt wire format. Wire format: [MEDCRYPT:v1::::] - patient_id is base64-encoded to avoid ':' delimiter collisions - nonce: 96-bit CSPRNG (os.urandom) - AAD: raw patient_id bytes (bound to ciphertext via GCM tag) """ if not patient_id: raise ValueError("patient_id must not be empty") nonce = os.urandom(12) # 96-bit CSPRNG nonce aesgcm = AESGCM(key.raw) aad = patient_id.encode("utf-8") ct_with_tag = aesgcm.encrypt(nonce, plaintext.encode("utf-8"), aad) # AESGCM appends 16-byte tag ciphertext = ct_with_tag[:-16] tag = ct_with_tag[-16:] # Base64-encode patient_id to avoid ':' in wire format pid_b64 = base64.b64encode(aad).decode("ascii") return ( f"[{WIRE_PREFIX}:{WIRE_VERSION}:{pid_b64}" f":{base64.b64encode(nonce).decode('ascii')}" f":{base64.b64encode(ciphertext).decode('ascii')}" f":{base64.b64encode(tag).decode('ascii')}]" ) ``` ### Technical Analysis The clinical message body is protected with AES-256-GCM, but `patient_id` is placed directly in the wire envelope using Base64. Base64 only converts binary data into a transport-safe textual representation; it does not provide confidentiality. The patient identifier is also used as authenticated additional data. AES-GCM authenticates AAD but does not encrypt it. Including the Base64 value in the transmitted envelope consequently allows anyone who can observe or obtain the message to recover the identifier without possessing the encryption key. This design exposes medical metadata and enables messages belonging to the same patient to be correlated. It conflicts w ...[truncated 1634 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
medcrypt.py:270
Finding

Incorrect GF(256) Inversion Breaks Emergency Key Reconstruction

Content
View full analysis
int: if a == 0: raise ValueError("Cannot invert zero in GF(256)") # Fermat's little theorem: a^(254) = a^(-1) in GF(2^8) result = a for _ in range(6): result = _gf256_mul(result, result) result = _gf256_mul(result, a) return result ``` ### Technical Analysis The comment correctly states that a nonzero GF(256) element can be inverted by raising it to the power 254. The implementation does not calculate that exponent. Starting with `result = a`, every loop iteration squares the current result and then multiplies it by `a`. If the current exponent is `e`, the next exponent is `2e + 1`. After six iterations, the sequence is: ```text 1 → 3 → 7 → 15 → 31 → 63 → 127 ``` The function therefore returns `a^127`, not `a^254`. `recover_key_from_shares()` uses this defective result when computing denominators in Lagrange interpolation. Consequently, valid Shamir shares can produce an incorrect reconstructed key. The defect undermines the documented 2-of-3 emergency break-glass functionality. This is a custom cryptographic implementation without the field-level validation required to establish correctness. ### Attack Path 1. A 32-byte master key is divided into three shares using `create_emergency_shares()`. 2. Direct access to the master key is subsequently lost or intentionally removed. 3. During an emergency, two authorized custodians submit valid shares to `recover_key_from_shares()`. 4. Recovery invokes `_gf256_inv()` while calculating the Lagrange basis. 5. The defective inverse produces incorrect interpolation coefficients. 6. The reconstructed byte sequence differs from the original master key. 7. Data protected by the original key remains unavailable during the emergency. This defect does not r ...[truncated 794 chars]
Remediation
View remediation
int: result = 1 base = a while exponent: if exponent & 1: result = _gf256_mul(result, base) base = _gf256_mul(base, base) exponent >>= 1 return result def _gf256_inv(a: int) -> int: if a == 0: raise ValueError("Cannot invert zero in GF(256)") return _gf256_pow(a, 254) ``` 3. Add an exhaustive field test for all nonzero byte values: ```python for value in range(1, 256): assert _gf256_mul(value, _gf256_inv(value)) == 1 ``` 4. Test randomized 32-byte keys across every valid threshold combination and verify byte-for-byte reconstruction. 5. Add negative tests for duplicate share coordinates, zero coordinates, malformed share lengths, insufficient shares, and inconsistent shares. 6. Authenticate shares and include version, threshold, share index, and key identifier metadata so corrupted or mixed share sets fail clearly. 7. Do not destroy the original key or rely on this emergency mechanism until recovery has been independently tested using an offline recovery drill. 8. Subject the complete key-recovery design to external cryptographic review before using it for medical records. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (9)

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The documentation advertises a QR-code/PBKDF2 shared-secret key exchange, but the implementation reportedly derives a key from a hardcoded password instead. In a medical-messaging context, this can cause operators and users to rely on a much weaker and materially different trust model than promised, leading to predictable key compromise and exposure of protected health information.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The documentation promises a 2-of-3 multisig break-glass emergency capability, but no such recovery or emergency-access path exists. In healthcare workflows, this can directly affect safety and compliance because responders may assume emergency access is available when it is not, or administrators may rely on nonexistent controls during incidents.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The threat-model section claims that compromised servers, stolen devices, unauthorized group members, and legal subpoenas are all mitigated, while the code reportedly only performs local encryption. These broad, unsupported assurances are dangerous in a medical-messaging skill because they can cause deployment in high-risk scenarios without the device security, access control, key custody, endpoint hardening, and governance controls actually required.

Content

No source excerpt is available for this finding.

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 · medcrypt.py (reported line 219)May include surrounding context.

python
# ─── Key Rotation ───

class KeyRing:
    """Monthly key rotation with deterministic salt per period.

    Salt is derived from HMAC(secret, month) — not raw SHA256 of secret —

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 · medcrypt.py (reported line 387)May include surrounding context.

python
# ─── Key Rotation ───

class KeyRing:
    """Monthly key rotation with deterministic salt per period.

    Salt is derived from HMAC(secret, month) — not raw SHA256 of secret —

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill claims monthly key rotation with 7-day backward compatibility, but the code reportedly has no rotation or legacy-key support. This creates a false sense of cryptographic hygiene and extends exposure if a key is compromised, especially where users expect regulated handling of sensitive medical data.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module advertises an 'encrypted audit log', but the implementation only keeps encrypted entries in an in-memory Python list. That can mislead integrators into believing they have durable, tamper-evident auditability for patient-physician events when the data is actually lost on process exit and can be modified at runtime.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The 'append-only audit trail' claim is contradicted by exposing self.entries as a mutable public list, which any caller can clear, reorder, replace, or forge. In a medical messaging context, this weakens accountability and incident investigation because activity records are not tamper resistant.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

This code includes natural-language clinical content entirely in Spanish, which can imply a fixed language/locale behavior. Under the policy rule, locale-specific language should either be optional for the user or clearly documented as a justified regional constraint.

Content

No source excerpt is available for this finding.