Severity by source
AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N
AC:H because exploitation requires the consuming application to pass unvalidated external input to path variables; PR:N as the attacker has no direct library access; no availability impact.
Primary rating from Vendor (https://github.com/jleehr/canto-saas-api).
CVSS VectorVendor: https://github.com/jleehr/canto-saas-api
Lifecycle Timeline
2DescriptionCVE.org
Summary
In affected versions, Request::buildRequestUrl() inserts path variables into the request URL without URL encoding (implode('/', $pathVariables)). All request classes implementing getPathVariables() are affected, e.g. GetContentDetailsRequest (scheme, contentId).
If a consuming application passes untrusted input (such as an ID taken from an HTTP request parameter) as a path variable, characters like ../, ? or # are sent verbatim and can change the path of the resulting API request.
Impact
An attacker who controls a path variable value can redirect the library's authenticated request - the Bearer access token is attached in AbstractEndpoint::sendRequest() - to a different API endpoint of the same Canto instance, causing unintended reads or writes with the privileges of the configured app. The impact depends on how the consuming application sources path variable values; applications that only pass trusted, validated IDs are not exploitable.
Patches
Fixed in 3.0.0: every path segment is encoded with rawurlencode() before being inserted into the request URL.
Workarounds
If you cannot upgrade, validate untrusted values before passing them to request classes, e.g. enforce an allowlist pattern such as ^[A-Za-z0-9_-]+$ for content IDs and schemes.
AnalysisAI
Unencoded path variable injection in jleehr/canto-saas-api (versions ≤ 2.0.0) allows URL path traversal sequences and delimiter characters to alter the destination endpoint of outbound API requests constructed by Request::buildRequestUrl(). When a consuming PHP application passes untrusted user input directly as path variables - such as scheme or contentId in GetContentDetailsRequest - characters including ../, ?, and # are inserted verbatim, silently redirecting the request to an unintended Canto API endpoint. Because the Bearer access token is unconditionally appended in AbstractEndpoint::sendRequest(), every such redirected request carries full application credentials, enabling unintended reads or writes scoped to the configured app's privileges. No public exploit has been identified at time of analysis, and exploitation is conditional on the consuming application's input-handling design.
Technical ContextAI
The affected library is the PHP Composer package jleehr/canto-saas-api, a client wrapper for the Canto SaaS digital asset management API. The root cause (CWE-74: Injection) lies in Request::buildRequestUrl(), which assembles API request paths by calling implode('/', $pathVariables) without applying rawurlencode() to individual segments. This means any special URL characters supplied by the caller pass through unescaped into the constructed URL. The Bearer access token is appended downstream in AbstractEndpoint::sendRequest(), making it available to any endpoint the URL resolves to - including manipulated paths. All request classes that implement getPathVariables() are affected; the advisory specifically names GetContentDetailsRequest with its scheme and contentId parameters. The fix in version 3.0.0 wraps each path segment with rawurlencode() before URL construction, preventing traversal sequences from altering the resolved path.
RemediationAI
Upgrade jleehr/canto-saas-api to version 3.0.0, which resolves the issue by encoding every path segment with rawurlencode() in Request::buildRequestUrl() before URL assembly. This fix is vendor-confirmed via GitHub Security Advisory GHSA-9qfv-wgh2-m6p8 at https://github.com/jleehr/canto-saas-api/security/advisories/GHSA-9qfv-wgh2-m6p8. For deployments that cannot immediately upgrade, the vendor-recommended workaround is to validate all untrusted input at the application layer before passing values to request classes - specifically, enforce an allowlist regular expression such as ^[A-Za-z0-9_-]+$ for path variable parameters like contentId and scheme. This workaround mitigates exploitation without touching the library but introduces a maintenance burden: any future request class with different valid character sets requires a corresponding validation rule, and any lapse in coverage re-exposes the underlying flaw. Upgrading to 3.0.0 remains the definitive remediation.
Same technique Information Disclosure
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-78905
GHSA-9qfv-wgh2-m6p8