Skip to content

fix(envd/auth): move expiration check before ConstantTimeCompare to close timing oracle - #3562

Open
AdaAibaby wants to merge 1 commit into
e2b-dev:mainfrom
AdaAibaby:fix/envd-auth-timing-oracle
Open

fix(envd/auth): move expiration check before ConstantTimeCompare to close timing oracle#3562
AdaAibaby wants to merge 1 commit into
e2b-dev:mainfrom
AdaAibaby:fix/envd-auth-timing-oracle

Conversation

@AdaAibaby

Copy link
Copy Markdown
Contributor

Problem

Closes #3561

validateSigning in packages/envd/internal/api/auth.go checked HMAC before signature expiration:

// BEFORE (vulnerable ordering)
if subtle.ConstantTimeCompare([]byte(expectedSignature), []byte(*signature)) != 1 {
    return errors.New("invalid signature")   // short-circuits here on wrong HMAC
}
if signatureExpiration != nil {
    if exp < time.Now().Unix() {
        return errors.New("signature is already expired")  // only reached on correct HMAC
    }
}
Request type Code path Latency
Wrong HMAC ConstantTimeCompare → return shorter
Correct HMAC + expired ConstantTimeCompare → expiration check → return measurably longer

An attacker can time responses to confirm a valid HMAC candidate without producing a non-expired token, narrowing brute-force search significantly. The envd file-signing key is long-lived (tied to sandbox lifetime) and a forged signature grants arbitrary file read/write to any running sandbox.

Fix

Move expiration before HMAC comparison. Expired requests are rejected immediately; only non-expired requests reach the timing-sensitive ConstantTimeCompare:

// AFTER (fixed ordering)
if signatureExpiration != nil {
    if exp < time.Now().Unix() {
        return errors.New("signature is already expired")
    }
}
if subtle.ConstantTimeCompare([]byte(expectedSignature), []byte(*signature)) != 1 {
    return errors.New("invalid signature")
}

No behaviour change for valid, non-expired requests. The ordering of error returns is preserved.

Changes

Single file, packages/envd/internal/api/auth.go: swap the two blocks and update comments (+10/-7 lines, logic-only).

…lose timing oracle

validateSigning checked HMAC first, then expiration. A correct-but-expired
signature traversed both checks; an incorrect signature short-circuited at
the HMAC step. The difference in response time is measurable and lets an
attacker confirm a valid HMAC candidate without ever needing to produce a
non-expired token, reducing brute-force cost for the file-signing key.

Move the expiration gate before ConstantTimeCompare so expired requests are
rejected before any HMAC work is done. Only non-expired requests now reach
the timing-sensitive comparison, eliminating the oracle.

Fixes: e2b-dev#3561
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(envd/auth): expiration check after ConstantTimeCompare leaks timing oracle in validateSigning

2 participants