mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-07-25 16:37:22 +02:00
Sanitize the cached ETag and index to satisfy CodeQL
Address two CodeQL findings on the per-test index downloader: - "File data in outbound network request": validate the cached ETag against the RFC 7232 grammar before sending it as If-None-Match, so the cache file's contents can't be injected into the request header. - "Network data written to file": cache the re-serialized JSON (JSON.stringify(JSON.parse(...))) instead of the raw response body, so only well-formed JSON produced by our own serializer is written.
This commit is contained in:
parent
d504000012
commit
c7dc7d7dd0
19
external/ccov/coverage_search.mjs
vendored
19
external/ccov/coverage_search.mjs
vendored
@ -111,7 +111,9 @@ async function refreshIndex() {
|
|||||||
const headers = {};
|
const headers = {};
|
||||||
if (hasCached && fs.existsSync(etagPath)) {
|
if (hasCached && fs.existsSync(etagPath)) {
|
||||||
const etag = fs.readFileSync(etagPath, "utf8").trim();
|
const etag = fs.readFileSync(etagPath, "utf8").trim();
|
||||||
if (etag) {
|
// Only forward a syntactically valid HTTP ETag (RFC 7232), so the cached
|
||||||
|
// file's contents can't be used to inject arbitrary data into the request.
|
||||||
|
if (/^(?:W\/)?"[\x21\x23-\x7e]*"$/.test(etag)) {
|
||||||
headers["If-None-Match"] = etag;
|
headers["If-None-Match"] = etag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,17 +136,20 @@ async function refreshIndex() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let data;
|
let text;
|
||||||
try {
|
try {
|
||||||
data = Buffer.from(await response.arrayBuffer());
|
text = await response.text();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
fallbackOrFail(error.message);
|
fallbackOrFail(error.message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the payload before caching it.
|
// Parse the payload before caching it, and cache the re-serialized result
|
||||||
|
// rather than the raw response body: only well-formed JSON produced by our
|
||||||
|
// own JSON.stringify is ever written to disk.
|
||||||
|
let serialized;
|
||||||
try {
|
try {
|
||||||
JSON.parse(data.toString("utf8"));
|
serialized = JSON.stringify(JSON.parse(text));
|
||||||
} catch {
|
} catch {
|
||||||
fallbackOrFail("the downloaded index is not valid JSON");
|
fallbackOrFail("the downloaded index is not valid JSON");
|
||||||
return;
|
return;
|
||||||
@ -154,7 +159,7 @@ async function refreshIndex() {
|
|||||||
try {
|
try {
|
||||||
fs.mkdirSync(path.dirname(indexPath), { recursive: true });
|
fs.mkdirSync(path.dirname(indexPath), { recursive: true });
|
||||||
const tmpPath = `${indexPath}.${process.pid}.tmp`;
|
const tmpPath = `${indexPath}.${process.pid}.tmp`;
|
||||||
fs.writeFileSync(tmpPath, data);
|
fs.writeFileSync(tmpPath, serialized);
|
||||||
fs.renameSync(tmpPath, indexPath);
|
fs.renameSync(tmpPath, indexPath);
|
||||||
|
|
||||||
const etag = response.headers.get("etag");
|
const etag = response.headers.get("etag");
|
||||||
@ -169,7 +174,7 @@ async function refreshIndex() {
|
|||||||
fallbackOrFail(error.message);
|
fallbackOrFail(error.message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.error(`Per-test index updated (${data.length} bytes).`);
|
console.error(`Per-test index updated (${serialized.length} bytes).`);
|
||||||
}
|
}
|
||||||
|
|
||||||
await refreshIndex();
|
await refreshIndex();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user