MLE-30263: Fix Uncaught Exception in getAccessToken Error Handler#1096
Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses a reliability/security issue in Cloud authentication by preventing uncaught exceptions from getAccessToken()’s async response handlers, and by routing token retrieval failures through operation.errorListener so callers see a rejected operation instead of a process crash.
Changes:
- Reworked
getAccessToken()error propagation to avoidthrowinside async event handlers and added request-level error handling. - Added defensive parsing/validation for token responses and improved token-error messaging.
- Added two regression tests covering token request network errors and 400 responses from the token endpoint.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| lib/requester.js | Reworks Cloud token retrieval error handling and response parsing/validation. |
| test-basic/cloud_authentication-test.js | Adds regression tests to assert token failures route through operation.errorListener. |
0f85c89 to
59285f2
Compare
59285f2 to
8e03c23
Compare
| try { | ||
| const responseValue = JSON.parse(responseBody); | ||
| if (!responseValue.access_token || !responseValue['.expires']) { | ||
| throw new Error('missing required token fields'); |
There was a problem hiding this comment.
throw new Error is used here. Should it be replaced with handleTokenError and return earlier?
|
|
||
| const expiration = new Date(responseValue['.expires']); | ||
| if (Number.isNaN(expiration.getTime())) { | ||
| throw new Error('invalid .expires value'); |
There was a problem hiding this comment.
throw new Error is used here. Should it be replaced with handleTokenError?
There was a problem hiding this comment.
I think that this is intentional to be picked up by req.on('error', (e) =>
There was a problem hiding this comment.
I think the throw new Error would be caught by catch(error) block (line 100) later. It then will call handleTokenError. So I think using throw new Error is not a bug, but replacing with handleTokenError and return earlier would be clearer and more explicit.
| operation.accessToken = responseValue.access_token; | ||
| operation.expiration = expiration; | ||
| operation.lockAccessToken = false; | ||
| authenticatedRequest(operation); |
There was a problem hiding this comment.
If authenticatedRequest throws for any reason unrelated to token parsing, that error will be caught and reported as "Invalid token endpoint response", which is misleading. Should authenticatedRequest be moved outside the try block?
There was a problem hiding this comment.
Makes Sense.. Fixed it!
8e03c23 to
0fb1c9f
Compare
Jira: MLE-30263
Severity: Medium | CVSS: 7.5 High | CWE: CWE-755
Problem
In Cloud authentication (
authType: 'CLOUD'),getAccessToken()threw errors from async event handlers (res.on('data')andres.on('error')). Throwing inside these callbacks can cause uncaught exceptions and crash the Node.js process instead of rejecting the calling operation.The implementation also double-wrapped errors (
new Error(existingError)), producing confusing error messages.Solution
Updated token retrieval error handling in
lib/requester.jsto use operation-level error propagation instead of throw-based async failures.handleTokenError(error, contextMessage)helper that:tokenErrorReported)operation.lockAccessTokenon failureoperation.errorListener(new Error(...))statusCode === 400throw path with:handleTokenError(null, 'Token endpoint returned 400: ...')try/catchaccess_tokenand.expiresoperation.errorListenerhandleTokenError(...).req.on('error', ...)handling for request/socket failures (e.g.ECONNRESET).Changes
File Change
lib/requester.js Reworked
getAccessToken()error paths to useoperation.errorListener; removed throw-based async failures; added request-error handling and token response validationtest-basic/cloud_authentication-test.js Added 2 regression tests for request network errors and token endpoint 400 responses
Tests
Pre-existing tests in
test-basic/cloud_authentication-test.jscontinue to pass (with one existing skipped test).New tests added:
should route token request network errors to operation.errorListenershould route token endpoint 400 responses to operation.errorListenerValidated result:
Testing instructions
Install dependencies
Run targeted cloud auth tests
If your default Node is not 22, run explicitly with Node 22