T09 · Insecure Skill Coding Practices
- Location
scripts/theijssen-cipher.js:31- Finding
Custom Repeating-XOR Encryption Lacks Cryptographic Authentication
- Content
View full analysis
Vulnerability Details
File Location:
scripts/theijssen-cipher.js:31-44,scripts/theijssen-cipher.js:128-152
Vulnerability Type: Insecure custom cryptographic construction
Risk Level: HighVulnerable Code
js function tripleXOR(data, key) { const [key1, key2, key3] = splitKey(key); const result = Buffer.alloc(data.length); for (let i = 0; i < data.length; i++) { let byte = data[i]; byte ^= key1[i % key1.length]; byte ^= key2[i % key2.length]; byte ^= key3[i % key3.length]; result[i] = byte; } return result; }js function encryptWithKey(data, keyFile) { const key = fs.readFileSync(keyFile); // Create metadata const metadata = JSON.stringify({ filename: 'data.bin', mimeType: 'application/octet-stream', timestamp: Date.now() }); const metadataBuffer = Buffer.from(metadata, 'utf8'); // Stage 1: Encrypt payload const encryptedPayload = tripleXOR(data, key); // Stage 2: Encrypt metadata const encryptedMetadata = tripleXOR(metadataBuffer, key); // Stage 3: Combine and encrypt package const payloadLength = Buffer.from(encryptedPayload.length.toString().padStart(10, '0'), 'utf8'); const packageData = Buffer.concat([ payloadLength, encryptedPayload, encryptedMetadata ]); const encryptedPackage = tripleXOR(packageData, key); return APP_VERSION + ':' + encryptedPackage.toString('base64'); }Technical Analysis
The implementation uses a custom repeating-XOR construction instead of a reviewed authenticated-encryption algorithm. Applying XOR three times does not create three independent cryptographic layers: it is algebraically equivalent to XOR with a single combined repeating keystream.
The same key file is reused for the pay ...[truncated 2656 chars]
- Remediation
View remediation
Remediation Suggestions
- Replace
tripleXORwith a reviewed authenticated-encryption algorithm:- AES-256-GCM; or
- XChaCha20-Poly1305.
- Generate a fresh cryptographically random nonce for every encrypted message. Store the nonce alongside the ciphertext; it does not need to be secret.
- Authenticate all metadata as either encrypted content or additional authenticated data.
- Derive a fixed-size encryption key from the key file using a reviewed KDF. Use HKDF when the key file already contains high-entropy random bytes, or a password-hardening KDF such as Argon2id or scrypt when accepting passwords.
- Define a versioned binary envelope containing the algorithm identifier, KDF parameters, salt where applicable, nonce, ciphertext, and authentication tag.
- Reject decryption before returning or writing any plaintext when authentication-tag verification fails.
- Add tests covering ciphertext modification, incorrect keys, nonce uniqueness, truncated input, malformed envelopes, and cross-message key reuse.
- Update
SKILL.mdto stop describing the current XOR construction as suitable for sensitive communication. Clearly mark legacy XOR data as unauthenticated and provide a migration path to a new format version.
- Replace
