Conversation
…encoding When a connection string contains a space or a stray `%`, parse() runs it through encodeURI() and then tries to undo the double encoding of escapes that were already there. The undo regex only matched two decimal digits, so escapes such as %2F, %3A, %2B or %3f stayed double encoded and came back literally: a password `s3cr%2Ft` became "s3cr%2Ft" instead of "s3cr/t" as soon as the URL also had, for example, `options=-c search_path=app`. Match any two hex digits, case-insensitively. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
If a connection string has a space or a stray
%anywhere in it,parse()runs it throughencodeURI()and then tries to undo the double encoding of escapes that were already there. The undo regex is/%25(\d\d)/g, so it only handles escapes made of two decimal digits.%40comes through fine, but%2F,%3A,%2B,%3fand any other escape with a hex letter stay double encoded and come back literally.This hits people who follow the usual advice to percent-encode special characters in the password and also put a readable
optionsvalue in the URL:Take away the space (
options=-c%20search_path%3Dapp) and the same password parses correctly, so the result depends on some other part of the URL. Against a local Postgres 14 with a role whose password iss3cr/t:,new Client({ connectionString: 'postgres://app:s3cr%2Ft%3A@127.0.0.1:55437/postgres?options=-c search_path=app' })fails on master withpassword authentication failed for user "app"and connects with this change (show search_pathreturnsapp). Generated cloud passwords often contain/,+and=, which are the escapes that break.The fix matches any two hex digits, case-insensitively:
/%25([0-9a-f]{2})/gi. An escape that was already valid is still restored exactly once, and an invalid%is still encoded as%25.Tests: added two cases to
packages/pg-connection-string/test/parse.ts, one with a space plus uppercase escapes and one with a stray%plus a lowercase escape. Both fail on master (expected 's3cr%2Ft%3A' to equal 's3cr/t:',expected 's3cr%2bt' to equal 's3cr+t') and pass with the fix. The full package suite passes (82) and the 100% coverage check passes. eslint and prettier are clean on the changed files.This PR was prepared with an AI coding assistant, and the failing tests, fix and local Postgres check above were all run before opening it.