T3MP3ST public launch build

This commit is contained in:
t3mp3st contributors committed 2026-07-03 10:57:20 -04:00
1 parent 972247b881
commit 184c7d4e59
1589 files changed
+57150 -506

No files matched your search

@@ -0,0 +1,27 @@
cve: POSTCUT-003
alias: JWT timing oracle — early-exit string compare leaks signature bytes
cwe_primary: CWE-208
cwe_acceptable: [CWE-208, CWE-203, CWE-385, CWE-1254, CWE-310]
target_file: source.js
vuln_lines: [9, 10, 11, 12, 13, 14, 15]
severity: high
vuln_class: timing_attack
exploit_pattern_regex: '(timing\s*attack|side[- ]channel|early[- ]exit|byte[- ]by[- ]byte|timing\s*oracle|crypto\.timingSafeEqual)'
must_mention_any:
- timing attack
- timing oracle
- early exit
- early-out
- short-circuit
- byte-by-byte
- timingSafeEqual
- side channel
- timing side
- character.code
points: 30
memorization_resistant: true
notes: |
Synthetic — novel. The "timingSafeStr" function is NOT timing-safe: it
returns on the first mismatched byte. Attacker can recover the expected
HMAC one byte at a time by measuring response time over the network.
Fix: use crypto.timingSafeEqual on equal-length buffers.
@@ -0,0 +1,32 @@
// JWT verifier — pre-fix internal auth lib.
// Custom HMAC because we don't want to depend on jsonwebtoken.
const crypto = require('crypto');
const SECRET = process.env.JWT_SECRET; // 32 bytes hex
function timingSafeStr(a, b) {
// Early-out check to avoid wasting CPU on short attacker inputs.
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a.charCodeAt(i) !== b.charCodeAt(i)) return false;
}
return true;
}
function verifyJwt(token) {
const [hdrB64, payB64, sigB64] = token.split('.');
if (!hdrB64 || !payB64 || !sigB64) return null;
const signingInput = `${hdrB64}.${payB64}`;
const expected = crypto.createHmac('sha256', SECRET)
.update(signingInput)
.digest('base64url');
if (!timingSafeStr(expected, sigB64)) {
return null;
}
return JSON.parse(Buffer.from(payB64, 'base64url').toString('utf8'));
}
module.exports = { verifyJwt };