Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,42 @@
<!-- This file is generated, please add to it using `knope document-change` in the client-library-templates repo -->
# Changelog

## 3.18.0 (2026-10-06)

### Features

#### Reject request paths that would leave the configured base URL

The low-level request path was joined onto the configured base URL with a resolving
join, which follows a path the way a browser follows a link. An absolute URL
(`https://host/x`) or a scheme-relative one (`//host/x`) replaced the configured
origin outright while the Authorization header was still attached, so an application
that passed untrusted input as a path could send its API token to a host of someone
else's choosing.

A path that is not a relative reference is now rejected before the join. Paths
containing dot segments remain valid: they resolve against the base URL and cannot
leave its origin.

#### Reject URL parameters that could change which endpoint is addressed

A URL parameter is a single path segment — a resource identity — but the escaping
applied to one varied by language, and in Go, Node, PHP and .NET there was none at
all. A value carrying path syntax could move a request to an endpoint the caller
never asked for: `find("../mandates")` reached the mandates collection, and
`find("?limit=500")` injected a query parameter.

Escaping alone cannot fix this, because `.` and `..` are dot segments that a path
resolver strips whether or not they are encoded, and an empty value addresses the
collection rather than one resource. Values that could change which endpoint is
addressed are therefore rejected rather than escaped: `/`, `?`, `#`, control
characters, `.`, `..` and the empty string now raise an error instead of producing a
request that quietly 404s. Everything else is escaped as before.

No valid GoCardless resource identity contains any of these characters, so correct
code is unaffected. Ruby and Java previously encoded `/` as `%2F` and sent the
request; they now raise.

## 3.17.0 (2026-10-05)

### Features
Expand Down
2 changes: 1 addition & 1 deletion gocardless_pro/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

from .client import Client

__version__ = '3.17.0'
__version__ = '3.18.0'

4 changes: 2 additions & 2 deletions gocardless_pro/api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ def _default_headers(self):
'Authorization': 'Bearer {0}'.format(self.access_token),
'Content-Type': 'application/json',
'GoCardless-Client-Library': 'gocardless-pro-python',
'GoCardless-Client-Version': '3.17.0',
'GoCardless-Client-Version': '3.18.0',
'User-Agent': self._user_agent(),
'GoCardless-Version': '2015-07-06',
}
Expand All @@ -201,7 +201,7 @@ def _user_agent(self):
python_version = '.'.join(platform.python_version_tuple()[0:2])
vm_version = '{}.{}.{}-{}{}'.format(*sys.version_info)
return ' '.join([
'gocardless-pro-python/3.17.0',
'gocardless-pro-python/3.18.0',
'python/{0}'.format(python_version),
'{0}/{1}'.format(platform.python_implementation(), vm_version),
'{0}/{1}'.format(platform.system(), platform.release()),
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

setup(
name = 'gocardless_pro',
version = '3.17.0',
version = '3.18.0',
packages = find_packages(exclude=['tests']),
install_requires = ['requests>=2.34.2'],
python_requires = '>=3.6',
Expand Down
Loading