Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1uQtRz-002Ewm-G0 for pgsql-general@arkaria.postgresql.org; Sun, 15 Jun 2025 19:55:31 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1uQtRv-00DkgG-3c for pgsql-general@arkaria.postgresql.org; Sun, 15 Jun 2025 19:55:27 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1uQtRu-00Dkg8-Md for pgsql-general@lists.postgresql.org; Sun, 15 Jun 2025 19:55:27 +0000 Received: from mail-pf1-x42a.google.com ([2607:f8b0:4864:20::42a]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1uQtRs-002EWG-31 for pgsql-general@postgresql.org; Sun, 15 Jun 2025 19:55:26 +0000 Received: by mail-pf1-x42a.google.com with SMTP id d2e1a72fcca58-7390d21bb1cso2921929b3a.2 for ; Sun, 15 Jun 2025 12:55:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1750017321; x=1750622121; darn=postgresql.org; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=OYrwaacpL3DobABx5qXRmgcPY8COrJwK9UVvA5Ue5mA=; b=ARXoQbVD42coj59ysgtrYbpFvKYQ2H3nt+gb0uEzfGY/CwcYzZyLYrQMifx+hHCjwc kr1dTlKe+igfsc7d7g0LeWjo2jHTXVPTW+9WSZLBl9NDzHHxYSbhL8lOwhh6roWtKFUB ImbBydBVULZKMetdhnJwLOgSsXH3N8YuUCpmIy0T5Pp5KmPx2C/+o5HSKPMrxBNhKVpK wsZ2xOD+wfUtD+l3vPiKcdJzxv2YnelC/V2VhpxtOgJPQ0gb7I4C7yE2hyeSGv9upS9b xTQQa3/ptLB1eAG9SD7DqviG6RdiF/V9OmjsuGjM4WLPb91TihvnS8Fs2ju5TwPkDkHZ uV1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750017321; x=1750622121; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=OYrwaacpL3DobABx5qXRmgcPY8COrJwK9UVvA5Ue5mA=; b=pajkmKgnOHrtP2zH6l/xJNBmMrfG4q7z6Nl16y0Aew+P4zgqIHMrdKFhNxyDrpv0qc l60ZV2sgSqMgUrry7OtoEReNtqVbPuC2BHSslqFoKV1zEiR8CRD+LfP0Zo8IpVtmD9T/ +FyzJuaXRTf4YMDPz14FUwqeJ4zeb7m4aperxcEzG3qiTnsOKfSIDhXsou7IIFO0e19g NgvtWOyIT/LgsZogO6bDUDPYRfpfhcJ603L0iPH+JbnN/WqY4wiq6SVcp+9vRYGmsXg5 IhJDvVqbgQEo2gS2wNNIsxwwcz5lwY+zFvTLNjUOPPd1y7K+zdgFf+ZOWmoPzX9HXoTF vzMQ== X-Gm-Message-State: AOJu0YxbDNbbGcNw+ko7tk3SNuRjsE74FnO/2sDPnn52MeNeDfXtqs01 gakWgCosasQb3PcJ/Ez6EkeKWWj6QVpjUgASQHPIwYNQHtypIUt2BBq+2Yt20G2iBm1AFDNFJt9 vYrC5IhmYPmqsb9i8OWdeCacT2r4G6ozEbOSk X-Gm-Gg: ASbGncvkmyo2t+shlmnjrHKbe4LgaTKM9kOTlbC5o6noJZ43F46l+ium4Dr5ngruRya jZsfHNISP8abkiAqiqvIXaC9KAJDXH7tWxeRFqVEoKDJu/xrm7LqcNN0JoFniOV61FvZ8pNErvq CDgmbBayGDkxkSybbaYm2g3dLnOePbn9FBbfLIiPVg/2IbsmlQ24yXnI46fZ3nvs9n/fDOWvkMl lVpkHAPZGOgV5Q= X-Google-Smtp-Source: AGHT+IGYPUOqVnDfFaDWEZIB8O9i51XWL06PBYTf2uztl7TgqVcobgmQcTjs2jso2I8iltAk4zf65ZquVW7LDI4Z6RA= X-Received: by 2002:a05:6a21:69b:b0:203:addb:5a29 with SMTP id adf61e73a8af0-21fbd5d84a3mr11460970637.40.1750017321369; Sun, 15 Jun 2025 12:55:21 -0700 (PDT) MIME-Version: 1.0 From: Phillip Diffley Date: Sun, 15 Jun 2025 21:55:10 +0200 X-Gm-Features: AX0GCFsWbyFztKoSkkTikwDpSE_y7o8NZgPRGzsHep_BgSH76_2wt9OBfrEPJWI Message-ID: Subject: Stably escaping an identifier To: pgsql-general@postgresql.org Content-Type: multipart/alternative; boundary="000000000000ca86910637a1a82c" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --000000000000ca86910637a1a82c Content-Type: text/plain; charset="UTF-8" I am in a situation where I need to run dynamically generated queries with identifiers from an untrusted source. For example SELECT * FROM WHERE = $1; We can use format('%I', ) to escape the identifier and avoid a security vulnerability, but if the provided identifier is already escaped, this introduces a problem. For example, SELECT format('%I', 'my identifier'); returns "my identifier", but SELECT format('%I', format('%I', 'my identifier')); returns """my identifier""" because it is escaping the previously added quotation marks. Is there a reliable way to determine if an identifier has already been escaped, or alternatively is there a function that will stably escape an identifier such that the identifier will not change if the function is called repeatedly? Thanks, Phillip --000000000000ca86910637a1a82c Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
I am in a situation where I need to = run dynamically generated queries with identifiers from an untrusted source= . For example
SELECT * FROM <untrusted_table_name> WHERE &l= t;untrusted_column_name> =3D $1;

We can use=C2= =A0format('%I', <untrusted_value>) to escape the identifier a= nd avoid a security vulnerability, but if the provided identifier is alread= y escaped, this introduces a problem. For example,
SELECT format(= '%I', 'my identifier');
returns=C2=A0"my ide= ntifier", but=C2=A0
SELECT format('%I', format('= %I', 'my identifier'));
returns=C2=A0""&quo= t;my identifier"""
because it is escaping the prev= iously added quotation marks.

Is there a reliable = way to determine if an identifier has already been escaped, or alternativel= y is there a function that will stably escape an identifier such that the i= dentifier will not change if the function is called repeatedly?
<= br>
Thanks,
Phillip
--000000000000ca86910637a1a82c--