Description
When using impit.fetch() with a FormData body, the generated multipart boundary uses an internal format (----formdata-impit-00000000.493) instead of the browser-standard WebKitFormBoundary format used by Chrome and Safari. Some servers fingerprint or validate the boundary prefix and reject requests that don't match the expected browser format, causing form fields to be silently dropped.
Steps to reproduce
import {Impit} from "impit";
const impit = new Impit({ browser: "chrome142" });
const form = new FormData();
form.append("field", "value");
const res = await impit.fetch("https://httpbin.org/post", {
method: "POST",
// headers: {"Content-Type":"multipart/form-data; boundary=----WebKitFormBoundaryKwwEDy3Dhp2M2R8S",}, // adding header manually causing form fields to be dropped
body: form,
});
const body = await res.json();
console.log(body);
Expected behavior
When browser: "chrome142" is set, the multipart boundary should match Chrome's format:
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary[A-Za-z0-9]{16}
Actual behavior
Content-Type: multipart/form-data; boundary=----formdata-impit-00000000.493
This boundary leaks the impit implementation detail and breaks fingerprint-sensitive servers.
Workaround
Manually build the raw body and set the Content-Type header explicitly:
import {Impit} from "impit";
function generateBoundary() {
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
return "----WebKitFormBoundary" +
Array.from({ length: 16 }, () => chars[Math.floor(Math.random() * chars.length)]).join("");
}
const boundary = generateBoundary();
const body = `--${boundary}\r\nContent-Disposition: form-data; name="field"\r\n\r\nvalue\r\n--${boundary}--\r\n`;
const impit = new Impit({
browser: "chrome142",
ignoreTlsErrors: true
});
const response =await impit.fetch("https://httpbin.org/post", {
method: "POST",
headers: { "Content-Type": `multipart/form-data; boundary=${boundary}` },
body,
});
const responseBody = await response.text();
console.log(response);
console.log(responseBody);
Environment
impit version: 0.13.0
browser profile: chrome142
runtime:
deno 2.7.12 (stable, release, x86_64-pc-windows-msvc)
v8 14.7.173.7-rusty
typescript 5.9.2
Suggested fix
When a browser profile is set, the boundary generator should match that browser's known format. For Chrome/Safari profiles, use ----WebKitFormBoundary + 16 alphanumeric chars. For Firefox, use ----geckoformboundary + hex string.
Description
When using
impit.fetch()with aFormDatabody, the generated multipart boundary uses an internal format (----formdata-impit-00000000.493) instead of the browser-standardWebKitFormBoundaryformat used by Chrome and Safari. Some servers fingerprint or validate the boundary prefix and reject requests that don't match the expected browser format, causing form fields to be silently dropped.Steps to reproduce
Expected behavior
When
browser: "chrome142"is set, the multipart boundary should match Chrome's format:Content-Type: multipart/form-data; boundary=----WebKitFormBoundary[A-Za-z0-9]{16}Actual behavior
Content-Type: multipart/form-data; boundary=----formdata-impit-00000000.493This boundary leaks the impit implementation detail and breaks fingerprint-sensitive servers.
Workaround
Manually build the raw body and set the Content-Type header explicitly:
Environment
Suggested fix
When a browser profile is set, the boundary generator should match that browser's known format. For Chrome/Safari profiles, use
----WebKitFormBoundary+ 16 alphanumeric chars. For Firefox, use----geckoformboundary+ hex string.