◐ Shell
clean mode source ↗

fix(security): harden deployment auth tokens by 3em0 · Pull Request #4760 · simstudioai/sim

Greptile Summary

This PR hardens deployment auth cookies by introducing versioned (v2) HMAC-signed tokens that bind the signature to the full SHA-256 of the encrypted password, removing the truncated password hash from the visible cookie payload and closing the unsigned-token forgery path reported in #4759.

  • deployment.ts: Adds AUTH_TOKEN_VERSION = 'v2', a passwordBinding() helper that folds sha256(encryptedPassword) into the HMAC input (not the payload), a hasValidTimestamp() helper, and a dual-path validator that accepts both new v2 tokens and legacy signed tokens for the existing 24-hour window.
  • deployment.test.ts: New test file covering forge rejection, password-change invalidation, payload tampering, expiry, and legacy compatibility; test helpers correctly replicate the production HMAC scheme using UTF-8 encoding, but the suite was not executed in CI (noted in the PR description).

Confidence Score: 3/5

The auth hardening logic is sound and the HMAC construction is correct, but a gap in hasValidTimestamp means forward-dated tokens pass expiry validation without restriction, and the test suite has not been run against the actual source.

The dual-path validator correctly routes v2 and legacy tokens, password binding is wired into the HMAC input rather than the cookie payload, and the test helpers faithfully mirror the production HMAC scheme. However, hasValidTimestamp returns true whenever Date.now() - createdAt is negative — any token carrying a future timestamp bypasses the 24-hour window. Non-browser callers or manually set cookies are unprotected by the browser maxAge bound.

apps/sim/lib/core/security/deployment.ts — the hasValidTimestamp function; apps/sim/lib/core/security/deployment.test.ts — confirm the suite passes in CI before merging.

Important Files Changed

Filename Overview
apps/sim/lib/core/security/deployment.ts Introduces v2 signed tokens that bind the HMAC to the full sha256 of the encrypted password (instead of exposing a truncated hash in the payload), keeps a backward-compatible legacy validation path, and adds hasValidTimestamp — but that helper accepts forward-dated timestamps, so tokens with createdAt in the future are never rejected.
apps/sim/lib/core/security/deployment.test.ts New test file covering the core security properties (forge rejection, password invalidation, tampering, expiry, legacy compatibility); helpers correctly mirror production UTF-8 HMAC logic, but tests were not executed and the future-timestamp edge case is untested.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Incoming token cookie] --> B[base64 decode]
    B --> C[split on lastColon: payload + sig]
    C --> D{parts0 === v2?}

    D -- Yes-v2 --> E{parts.length === 4?}
    E -- No --> REJECT1[return false]
    E -- Yes --> F[HMAC over payload + sha256-encryptedPassword]
    F --> G{sig matches?}
    G -- No --> REJECT2[return false]
    G -- Yes --> H{storedId === deploymentId?}
    H -- No --> REJECT3[return false]
    H -- Yes --> I{hasValidTimestamp?}
    I -- No --> REJECT4[return false]
    I -- Yes --> ACCEPT1[return true]

    D -- No-legacy --> J{parts.length === 4?}
    J -- No --> REJECT5[return false]
    J -- Yes --> K[HMAC over payload only]
    K --> L{sig matches?}
    L -- No --> REJECT6[return false]
    L -- Pass --> M{storedId === deploymentId?}
    M -- No --> REJECT7[return false]
    M -- Yes --> N{pwSlot matches?}
    N -- No --> REJECT8[return false]
    N -- Yes --> O{hasValidTimestamp?}
    O -- No --> REJECT9[return false]
    O -- Yes --> ACCEPT2[return true]

    subgraph note [hasValidTimestamp - future timestamps accepted]
        I
        O
    end
Loading

Reviews (1): Last reviewed commit: "fix(security): harden deployment auth to..." | Re-trigger Greptile