From e5168e88e4b2db35bd78ae8af169a9b76a89ca7b Mon Sep 17 00:00:00 2001 From: Fang-Pen Lin Date: Fri, 7 Nov 2025 11:01:20 -0800 Subject: [PATCH] Use re2 for identifier validation --- backend/src/ee/services/pki-acme/pki-acme-fns.ts | 9 +++++++++ backend/src/ee/services/pki-acme/pki-acme-schemas.ts | 12 ++---------- backend/src/ee/services/pki-acme/pki-acme-service.ts | 7 +++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/backend/src/ee/services/pki-acme/pki-acme-fns.ts b/backend/src/ee/services/pki-acme/pki-acme-fns.ts index d82877891..eabfc7802 100644 --- a/backend/src/ee/services/pki-acme/pki-acme-fns.ts +++ b/backend/src/ee/services/pki-acme/pki-acme-fns.ts @@ -1,3 +1,5 @@ +import { getConfig } from "@app/lib/config/env"; +import RE2 from "re2"; import { z } from "zod"; import { getConfig } from "@app/lib/config/env"; @@ -17,3 +19,10 @@ export const extractAccountIdFromKid = (kid: string, profileId: string): string } return z.string().uuid().parse(kid.slice(kidPrefix.length)); }; + +export const validateDnsIdentifier = (identifier: string): boolean => { + // DNS label pattern: 1-63 chars, alphanumeric or hyphen, but not starting or ending with hyphen + const labelPattern = new RE2(/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?$/); + const labels = identifier.split("."); + return labels.every((label) => label.length >= 1 && label.length <= 63 && labelPattern.test(label)); +}; diff --git a/backend/src/ee/services/pki-acme/pki-acme-schemas.ts b/backend/src/ee/services/pki-acme/pki-acme-schemas.ts index baa686e59..58ca7e833 100644 --- a/backend/src/ee/services/pki-acme/pki-acme-schemas.ts +++ b/backend/src/ee/services/pki-acme/pki-acme-schemas.ts @@ -1,4 +1,3 @@ -import RE2 from "re2"; import { z } from "zod"; export enum AcmeIdentifierType { @@ -84,19 +83,12 @@ export const CreateAcmeAccountResponseSchema = z.object({ orders: z.string().optional() }); -export const ValidDNSIdentifierRegex = /^(?!-)[A-Za-z0-9-]{1,63}(? { - // DNS label pattern: 1-63 chars, alphanumeric or hyphen, but not starting or ending with hyphen - const labelPattern = new RE2(/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?$/); - const labels = val.split("."); - return labels.every((label) => label.length >= 1 && label.length <= 63 && labelPattern.test(label)); - }, "Invalid DNS identifier") + type: z.string(), + value: z.string() }) ), notBefore: z.string().optional(), diff --git a/backend/src/ee/services/pki-acme/pki-acme-service.ts b/backend/src/ee/services/pki-acme/pki-acme-service.ts index 3190f98ef..51f530264 100644 --- a/backend/src/ee/services/pki-acme/pki-acme-service.ts +++ b/backend/src/ee/services/pki-acme/pki-acme-service.ts @@ -43,7 +43,7 @@ import { AcmeServerInternalError, AcmeUnsupportedIdentifierError } from "./pki-acme-errors"; -import { buildUrl, extractAccountIdFromKid } from "./pki-acme-fns"; +import { buildUrl, extractAccountIdFromKid, validateDnsIdentifier } from "./pki-acme-fns"; import { TPkiAcmeOrderAuthDALFactory } from "./pki-acme-order-auth-dal"; import { TPkiAcmeOrderDALFactory } from "./pki-acme-order-dal"; import { @@ -53,8 +53,7 @@ import { AcmeIdentifierType, AcmeOrderStatus, CreateAcmeAccountBodySchema, - ProtectedHeaderSchema, - ValidDNSIdentifierRegex + ProtectedHeaderSchema } from "./pki-acme-schemas"; import { TAcmeOrderResource, @@ -497,7 +496,7 @@ export const pkiAcmeServiceFactory = ({ if ( payload.identifiers.some( (identifier) => - !ValidDNSIdentifierRegex.test(identifier.value) || + !validateDnsIdentifier(identifier.value) || isPrivateIp(identifier.value) || (!getConfig().isDevelopmentMode && identifier.value.toLowerCase() === "localhost") )