Skip to content

chore: replace scmp with crypto.timingSafeEqual#1184

Open
Methuselah96 wants to merge 1 commit intotwilio:mainfrom
Methuselah96:scmp
Open

chore: replace scmp with crypto.timingSafeEqual#1184
Methuselah96 wants to merge 1 commit intotwilio:mainfrom
Methuselah96:scmp

Conversation

@Methuselah96
Copy link
Copy Markdown
Contributor

@Methuselah96 Methuselah96 commented Mar 24, 2026

Fixes #1168

scmp is now deprecated and is equivalent to crypto.timingSafeEqual (which is supported by Node.js >=6.6.0)

Checklist

  • I acknowledge that all my contributions will be made under the project's license
  • I have made a material change to the repo (functionality, testing, spelling, grammar)
  • I have read the Contribution Guidelines and my PR follows them
  • I have titled the PR appropriately
  • I have updated my branch with the main branch
  • I have added tests that prove my fix is effective or that my feature works
  • I have added the necessary documentation about the functionality in the appropriate .md file
  • I have added inline documentation to the code I modified

@Methuselah96
Copy link
Copy Markdown
Contributor Author

Investigating failing tests

@Methuselah96 Methuselah96 marked this pull request as draft March 24, 2026 15:29
@Methuselah96 Methuselah96 marked this pull request as ready for review March 24, 2026 15:43
@Methuselah96
Copy link
Copy Markdown
Contributor Author

Fixed

Comment thread src/webhooks/webhooks.ts Outdated
Comment on lines +274 to +275
if (a.length !== b.length) return false;
return crypto.timingSafeEqual(a, b);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning earlier would be unsafe because it would leak timing info. Suggest doing the HMAC beforehand:

const salt = crypto.randomBytes(42);
return crypto.timingSafeEqual(
  crypto.createHmac("sha256", salt).update(a).digest(),
  crypto.createHmac("sha256", salt).update(b).digest(),
);

Copy link
Copy Markdown
Contributor Author

@Methuselah96 Methuselah96 Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm out of my depth here, but scmp was returning earlier based on the length, so seems like this might be a pre-existing issue

Copy link
Copy Markdown
Contributor Author

@Methuselah96 Methuselah96 Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to this comment, it's okay to check the length first and return early if they're not equal

Copy link
Copy Markdown
Contributor Author

@Methuselah96 Methuselah96 Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, according to this article, you should not return early and instead still compare two values. That seems like a more understandable solution to me, so I've updated the PR to that solution.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both negate when lengths differ or HMAC works.

The reason I suggested a later approach is that it is not always clear whether the input is from a or b, thus making it error-prone without context.

btw: I wrote that code snippet on Cloudflare docs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I've updated the variable names to more clearly indicate which input is the user value and which one is the secret value and verified that we are passing the arguments in the correct order that matches the parameter order

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that it has only been used internally, I think it is good enough to make a cut. LGTM

Thanks.

@Emperiusm
Copy link
Copy Markdown

+1 from a downstream consumer.

We hit npm warn deprecated scmp@2.1.0: Just use Node.js's crypto.timingSafeEqual() during a transitive-deps audit and confirmed the only path to it is twilio@5.x → scmp. v6.0.1 still pulls scmp, so the deprecation can't be cleared by bumping the major. This PR is the only path forward — would love to see it land.

If maintainers want a small validation harness, the existing webhook/auth-token signature validators that route through scmp are well-covered by the repo's tests, so a swap-only PR like this one should be low-risk under those.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace scmp with node crypto.timingSafeEqual()

3 participants