fix(respect): record request bodies in the HAR postData entry - #2992
fix(respect): record request bodies in the HAR postData entry#2992ariesclark wants to merge 1 commit into
Conversation
🦋 Changeset detectedLatest commit: 8c65702 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
@ariesclark If I understand correctly, the main issue is that the postData field is missing. Is that right? |
|
From the description: Actually, the HAR is passed through conditionallyMaskSecrets before being written |
| )?.value; | ||
|
|
||
| return { | ||
| mimeType: typeof contentType === 'string' ? contentType : 'application/octet-stream', |
There was a problem hiding this comment.
Fetch sets this content type itself when a URLSearchParams body is sent without an explicit header:
const fallbackMimeType =
body instanceof URLSearchParams
? 'application/x-www-form-urlencoded;charset=UTF-8'
: 'application/octet-stream';
return {
mimeType: typeof contentType === 'string' ? contentType : fallbackMimeType,
text,
};
| headersSize: -1, | ||
| bodySize: -1, | ||
| postData: {}, | ||
| bodySize: postData.text === undefined ? -1 : Buffer.byteLength(postData.text), |
There was a problem hiding this comment.
| bodySize: postData.text === undefined ? -1 : Buffer.byteLength(postData.text), | |
| // -1 means "not available": a body was sent but not recorded (for example FormData). | |
| bodySize: | |
| postData.text !== undefined ? Buffer.byteLength(postData.text) : options.body ? -1 : 0, | |
| ...(postData.text !== undefined && { postData }), |
Yup, that's right, |
What/Why/How?
withHarrecordedpostData: {}for every request, so a HAR fromrespect --har-outputnever contained the request body. Replaying that capture throughdriftskips request-body validation and reports no problems. Missing data reads as a pass.buildPostDataserializes the body and reads the mime type from the request'scontent-type, going throughbuildHeadersso it treats every header shape alike. It records only text bodies, omittingFormData, streams, and binary rather than stringifying them to[object Object].request.bodySizenow carries the byte length instead of-1.Reference
None.
Testing
build-post-data.test.tscovers the content-type sources, theapplication/octet-streamfallback, and the cases that must record nothing: no body, empty string,Buffer,FormData, plain object.Check yourself
Security
The HAR now stores request bodies verbatim, so capturing a login flow puts credentials in the file. The capture already recorded headers and response bodies unmasked, so this widens an existing exposure rather than adding a new kind.
Note
Medium Risk
HAR files now store request bodies verbatim (including credentials in login flows), widening an existing capture exposure; behavior change is localized to respect HAR logging with conservative omission for non-text bodies.
Overview
Fixes HAR capture for
respect --har-outputso request bodies are no longer always recorded as emptypostData: {}, which causeddriftreplay to skip request-body validation and look successful when nothing was checked.A new
buildPostDatahelper builds HARpostDatafromoptions.bodyandcontent-type(via the samebuildHeaderspaths as the rest of the HAR). It records string andURLSearchParamsbodies, usesapplication/octet-streamwhen no content type is set, and omits bodies it cannot safely serialize (no body, empty string,Buffer,FormData, plain objects).withHarnow setsrequest.postDatafrom that helper andrequest.bodySizeto the UTF-8 byte length when text is present (otherwise-1).Reviewed by Cursor Bugbot for commit 8c65702. Bugbot is set up for automated code reviews on this repo. Configure here.