fix(infra): bound ed25519 base64url decode input length (#104921)

This commit is contained in:
thomas.szbay
2026-07-12 13:39:35 +08:00
committed by GitHub
parent 8f8b44a3ce
commit 4dfffeb4ce
2 changed files with 23 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
import { describe, expect, it } from "vitest";
import { base64UrlDecode, base64UrlEncode } from "./ed25519-signature.ts";
describe("base64UrlDecode", () => {
it("decodes a fixed-size ed25519 public key without throwing", () => {
const key = base64UrlEncode(Buffer.alloc(32, 7));
expect(base64UrlDecode(key).length).toBe(32);
});
it("throws on input exceeding the maximum allowed length", () => {
// MAX_BASE64URL_DECODE_INPUT_LENGTH is 4096; 5000 is safely over it.
const oversized = "A".repeat(5000);
expect(() => base64UrlDecode(oversized)).toThrow(/maximum allowed length/);
});
});

View File

@@ -7,7 +7,15 @@ export function base64UrlEncode(buf: Buffer): string {
return buf.toString("base64").replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/g, "");
}
// Ed25519 public keys and signatures are fixed-size (<= ~86 base64url chars),
// so a caller passing far larger input is almost certainly malformed or abusive.
// Bound the decoded buffer to keep a single request from allocating arbitrary memory.
const MAX_BASE64URL_DECODE_INPUT_LENGTH = 4096;
export function base64UrlDecode(input: string): Buffer {
if (input.length > MAX_BASE64URL_DECODE_INPUT_LENGTH) {
throw new Error("base64url input exceeds the maximum allowed length");
}
const normalized = input.replaceAll("-", "+").replaceAll("_", "/");
const padded = normalized + "=".repeat((4 - (normalized.length % 4)) % 4);
return Buffer.from(padded, "base64");